Cleanup overriding images

This commit is contained in:
Sean Lilley 2017-07-28 16:56:28 -04:00
parent e54f3af37f
commit 3da691df62
9 changed files with 227 additions and 147 deletions

View File

@ -131,10 +131,34 @@ if (!defined(gltfPath)) {
gltfPath = path.join(path.dirname(objPath), modelName + extension); gltfPath = path.join(path.dirname(objPath), modelName + extension);
} }
var overridingImages = {
metallicRoughnessOcclusionTexture : argv.metallicRoughnessOcclusionTexture,
specularGlossinessTexture : argv.specularGlossinessTexture,
occlusionTexture : argv.occlusionTexture,
normalTexture : argv.normalTexture,
baseColorTexture : argv.baseColorTexture,
emissiveTexture : argv.emissiveTexture
};
var options = {
binary : argv.binary,
separate : argv.separate,
separateTextures : argv.separateTextures,
checkTransparency : argv.checkTransparency,
secure : argv.secure,
inputUpAxis : argv.inputUpAxis,
outputUpAxis : argv.outputUpAxis,
packOcclusion : argv.packOcclusion,
metallicRoughness : argv.metallicRoughness,
specularGlossiness : argv.specularGlossiness,
materialsCommon : argv.materialsCommon,
overridingImages : overridingImages
};
console.time('Total'); console.time('Total');
try { try {
obj2gltf(objPath, gltfPath, argv) obj2gltf(objPath, gltfPath, options)
.then(function() { .then(function() {
console.timeEnd('Total'); console.timeEnd('Total');
}) })

18
lib/Image.js Normal file
View File

@ -0,0 +1,18 @@
'use strict';
module.exports = Image;
/**
* Stores image data and properties.
*
* @private
*/
function Image() {
this.transparent = false;
this.source = undefined;
this.extension = undefined;
this.path = undefined;
this.decoded = undefined;
this.width = undefined;
this.height = undefined;
}

View File

@ -2,6 +2,7 @@
var Cesium = require('cesium'); var Cesium = require('cesium');
var path = require('path'); var path = require('path');
var getBufferPadded = require('./getBufferPadded'); var getBufferPadded = require('./getBufferPadded');
var Image = require('./Image');
var Material = require('./Material'); var Material = require('./Material');
var CesiumMath = Cesium.Math; var CesiumMath = Cesium.Math;
@ -20,13 +21,13 @@ module.exports = createGltf;
* @param {Boolean} options.metallicRoughness The values in the mtl file are already metallic-roughness PBR values and no conversion step should be applied. Metallic is stored in the Ks and map_Ks slots and roughness is stored in the Ns and map_Ns slots. * @param {Boolean} options.metallicRoughness The values in the mtl file are already metallic-roughness PBR values and no conversion step should be applied. Metallic is stored in the Ks and map_Ks slots and roughness is stored in the Ns and map_Ns slots.
* @param {Boolean} options.specularGlossiness The values in the mtl file are already specular-glossiness PBR values and no conversion step should be applied. Specular is stored in the Ks and map_Ks slots and glossiness is stored in the Ns and map_Ns slots. The glTF will be saved with the KHR_materials_pbrSpecularGlossiness extension. * @param {Boolean} options.specularGlossiness The values in the mtl file are already specular-glossiness PBR values and no conversion step should be applied. Specular is stored in the Ks and map_Ks slots and glossiness is stored in the Ns and map_Ns slots. The glTF will be saved with the KHR_materials_pbrSpecularGlossiness extension.
* @param {Boolean} options.materialsCommon The glTF will be saved with the KHR_materials_common extension. * @param {Boolean} options.materialsCommon The glTF will be saved with the KHR_materials_common extension.
* @param {Object[]} options.overridingImages An array of images that override images in the .mtl file. * @param {Object} [options.overridingImages] An object containing image paths that override material values defined in the .mtl file. This is often convenient in workflows where the .mtl does not exist or is not set up to use PBR materials. Intended for models with a single material.
* @param {String} [options.metallicRoughnessOcclusionTexture] Path to the metallic-roughness-occlusion texture used by the model, where occlusion is stored in the red channel, roughness is stored in the green channel, and metallic is stored in the blue channel. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. The model will be saved with a pbrMetallicRoughness material. * @param {String} [options.overridingImages.metallicRoughnessOcclusionTexture] Path to the metallic-roughness-occlusion texture, where occlusion is stored in the red channel, roughness is stored in the green channel, and metallic is stored in the blue channel. The model will be saved with a pbrMetallicRoughness material.
* @param {String} [options.specularGlossinessTexture] Path to the specular-glossiness texture used by the model, where specular color is stored in the red, green, and blue channels and specular glossiness is stored in the alpha channel. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. The model will be saved with a material using the KHR_materials_pbrSpecularGlossiness extension. * @param {String} [options.overridingImages.specularGlossinessTexture] Path to the specular-glossiness texture, where specular color is stored in the red, green, and blue channels and specular glossiness is stored in the alpha channel. The model will be saved with a material using the KHR_materials_pbrSpecularGlossiness extension.
* @param {String} [options.occlusionTexture] Path to the occlusion texture used by the model. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. Ignored if metallicRoughnessOcclusionTexture is also set. * @param {String} [options.overridingImages.occlusionTexture] Path to the occlusion texture. Ignored if metallicRoughnessOcclusionTexture is also set.
* @param {String} [options.normalTexture] Path to the normal texture used by the model. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. * @param {String} [options.overridingImages.normalTexture] Path to the normal texture.
* @param {String} [options.baseColorTexture] Path to the baseColor/diffuse texture used by the model. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. * @param {String} [options.overridingImages.baseColorTexture] Path to the baseColor/diffuse texture.
* @param {String} [options.emissiveTexture] Path to the emissive texture used by the model. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. * @param {String} [options.overridingImages.emissiveTexture] Path to the emissive texture.
* @param {Boolean} options.logger A callback function for handling logged messages. Defaults to console.log. * @param {Boolean} options.logger A callback function for handling logged messages. Defaults to console.log.
* @returns {Object} A glTF asset. * @returns {Object} A glTF asset.
* *
@ -158,9 +159,10 @@ function addBuffers(gltf, bufferState) {
}); });
} }
function getImage(images, imagePath, overrideImagePath, options) { function getImage(images, imagePath, overridingImage) {
images = options.overridingImages.concat(images); if (defined(overridingImage)) {
imagePath = defaultValue(overrideImagePath, imagePath); return overridingImage;
}
var imagesLength = images.length; var imagesLength = images.length;
for (var i = 0; i < imagesLength; ++i) { for (var i = 0; i < imagesLength; ++i) {
var image = images[i]; var image = images[i];
@ -383,15 +385,12 @@ function createMetallicRoughnessTexture(gltf, metallicImage, roughnessImage, occ
} }
var imageName = imageNames.join('_'); var imageName = imageNames.join('_');
var image = { var image = new Image();
transparent : false, image.extension = '.png';
source : undefined, image.path = imageName;
extension : '.png', image.decoded = pixels;
path : imageName, image.width = width;
decoded : pixels, image.height = height;
width : width,
height : height
};
return getTexture(gltf, image); return getTexture(gltf, image);
} }
@ -448,15 +447,12 @@ function createSpecularGlossinessTexture(gltf, specularImage, glossinessImage, o
} }
var imageName = imageNames.join('_'); var imageName = imageNames.join('_');
var image = { var image = new Image();
transparent : true, image.extension = '.png';
source : undefined, image.path = imageName;
extension : '.png', image.decoded = pixels;
path : imageName, image.width = width;
decoded : pixels, image.height = height;
width : width,
height : height
};
return getTexture(gltf, image); return getTexture(gltf, image);
} }
@ -465,12 +461,13 @@ function createSpecularGlossinessMaterial(gltf, images, material, options) {
var materialName = material.name; var materialName = material.name;
// The texture paths supplied in the .mtl may be overriden by the texture paths supplied in options // The texture paths supplied in the .mtl may be overriden by the texture paths supplied in options
var emissiveImage = getImage(images, material.emissiveTexture, options.emissiveTexture, options); var overridingImages = options.overridingImages;
var normalImage = getImage(images, material.normalTexture, options.normalTexture, options); var emissiveImage = getImage(images, material.emissiveTexture, overridingImages.emissiveTexture, options);
var occlusionImage = getImage(images, material.ambientTexture, options.occlusionTexture, options); var normalImage = getImage(images, material.normalTexture, overridingImages.normalTexture, options);
var diffuseImage = getImage(images, material.diffuseTexture, options.baseColorTexture, options); var occlusionImage = getImage(images, material.ambientTexture, overridingImages.occlusionTexture, options);
var specularImage = getImage(images, material.specularTexture, options.specularGlossinessTexture, options); var diffuseImage = getImage(images, material.diffuseTexture, overridingImages.baseColorTexture, options);
var glossinessImage = getImage(images, material.specularShininessTexture, options.specularGlossinessTexture, options); var specularImage = getImage(images, material.specularTexture, overridingImages.specularGlossinessTexture, options);
var glossinessImage = getImage(images, material.specularShininessTexture, overridingImages.specularGlossinessTexture, options);
var emissiveTexture = getTexture(gltf, emissiveImage); var emissiveTexture = getTexture(gltf, emissiveImage);
var normalTexture = getTexture(gltf, normalImage); var normalTexture = getTexture(gltf, normalImage);
@ -478,7 +475,7 @@ function createSpecularGlossinessMaterial(gltf, images, material, options) {
var diffuseTexture = getTexture(gltf, diffuseImage); var diffuseTexture = getTexture(gltf, diffuseImage);
var specularGlossinessTexture; var specularGlossinessTexture;
if (defined(options.specularGlossinessTexture)) { if (defined(overridingImages.specularGlossinessTexture)) {
specularGlossinessTexture = getTexture(gltf, specularImage); specularGlossinessTexture = getTexture(gltf, specularImage);
} else { } else {
specularGlossinessTexture = createSpecularGlossinessTexture(gltf, specularImage, glossinessImage, options); specularGlossinessTexture = createSpecularGlossinessTexture(gltf, specularImage, glossinessImage, options);
@ -542,26 +539,27 @@ function createSpecularGlossinessMaterial(gltf, images, material, options) {
function createMetallicRoughnessMaterial(gltf, images, material, options) { function createMetallicRoughnessMaterial(gltf, images, material, options) {
var materialName = material.name; var materialName = material.name;
// The texture paths supplied in the .mtl may be overriden by the texture paths supplied in options // The texture paths supplied in the .mtl may be over var overridingImages = options.overridingImages;
var emissiveImage = getImage(images, material.emissiveTexture, options.emissiveTexture, options); var overridingImages = options.overridingImages;
var normalImage = getImage(images, material.normalTexture, options.normalTexture, options); var emissiveImage = getImage(images, material.emissiveTexture, overridingImages.emissiveTexture);
var occlusionImage = getImage(images, material.ambientTexture, options.metallicRoughnessOcclusionTexture, options); var normalImage = getImage(images, material.normalTexture, overridingImages.normalTexture);
var baseColorImage = getImage(images, material.diffuseTexture, options.baseColorTexture, options); var occlusionImage = getImage(images, material.ambientTexture, overridingImages.metallicRoughnessOcclusionTexture);
var metallicImage = getImage(images, material.specularTexture, options.metallicRoughnessOcclusionTexture, options); var baseColorImage = getImage(images, material.diffuseTexture, overridingImages.baseColorTexture);
var roughnessImage = getImage(images, material.specularShininessTexture, options.metallicRoughnessOcclusionTexture, options); var metallicImage = getImage(images, material.specularTexture, overridingImages.metallicRoughnessOcclusionTexture);
var roughnessImage = getImage(images, material.specularShininessTexture, overridingImages.metallicRoughnessOcclusionTexture);
var emissiveTexture = getTexture(gltf, emissiveImage); var emissiveTexture = getTexture(gltf, emissiveImage);
var normalTexture = getTexture(gltf, normalImage); var normalTexture = getTexture(gltf, normalImage);
var baseColorTexture = getTexture(gltf, baseColorImage); var baseColorTexture = getTexture(gltf, baseColorImage);
var metallicRoughnessTexture; var metallicRoughnessTexture;
if (defined(options.metallicRoughnessOcclusionTexture)) { if (defined(overridingImages.metallicRoughnessOcclusionTexture)) {
metallicRoughnessTexture = getTexture(gltf, metallicImage); metallicRoughnessTexture = getTexture(gltf, metallicImage);
} else { } else {
metallicRoughnessTexture = createMetallicRoughnessTexture(gltf, metallicImage, roughnessImage, occlusionImage, options); metallicRoughnessTexture = createMetallicRoughnessTexture(gltf, metallicImage, roughnessImage, occlusionImage, options);
} }
var packOcclusion = (defined(occlusionImage) && options.packOcclusion) || defined(options.metallicRoughnessOcclusionTexture); var packOcclusion = (defined(occlusionImage) && options.packOcclusion) || defined(overridingImages.metallicRoughnessOcclusionTexture);
var occlusionTexture = packOcclusion ? metallicRoughnessTexture : getTexture(gltf, occlusionImage); var occlusionTexture = packOcclusion ? metallicRoughnessTexture : getTexture(gltf, occlusionImage);
var emissiveFactor = getEmissiveFactor(material); var emissiveFactor = getEmissiveFactor(material);

View File

@ -5,6 +5,7 @@ var jpeg = require('jpeg-js');
var path = require('path'); var path = require('path');
var PNG = require('pngjs').PNG; var PNG = require('pngjs').PNG;
var Promise = require('bluebird'); var Promise = require('bluebird');
var Image = require('./Image');
var defaultValue = Cesium.defaultValue; var defaultValue = Cesium.defaultValue;
var defined = Cesium.defined; var defined = Cesium.defined;
@ -12,13 +13,13 @@ var defined = Cesium.defined;
module.exports = loadImage; module.exports = loadImage;
/** /**
* Load an image file and get information about it. * Load an image file.
* *
* @param {String} imagePath Path to the image file. * @param {String} imagePath Path to the image file.
* @param {Object} options An object with the following properties: * @param {Object} options An object with the following properties:
* @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.checkTransparency=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel.
* @param {Boolean} [options.decode=false] Decode image. * @param {Boolean} [options.decode=false] Decode image.
* @returns {Promise} A promise resolving to the image information, or undefined if the file doesn't exist. * @returns {Promise} A promise resolving to an Image object.
* *
* @private * @private
*/ */
@ -30,30 +31,29 @@ function loadImage(imagePath, options) {
return fsExtra.readFile(imagePath) return fsExtra.readFile(imagePath)
.then(function(data) { .then(function(data) {
var extension = path.extname(imagePath).toLowerCase(); var extension = path.extname(imagePath).toLowerCase();
var image = new Image();
image.source = data;
image.extension = extension;
image.path = imagePath;
var info = { var decodePromise;
transparent : false,
source : data,
extension : extension,
path : imagePath,
decoded : undefined,
width : undefined,
height : undefined
};
if (extension === '.png') { if (extension === '.png') {
return getPngInfo(data, info, options); decodePromise = decodePng(image, options);
} else if (extension === '.jpg' || extension === '.jpeg') { } else if (extension === '.jpg' || extension === '.jpeg') {
return getJpegInfo(data, info, options); decodePromise = decodeJpeg(image, options);
} }
return info; if (defined(decodePromise)) {
return decodePromise.thenReturn(image);
}
return image;
}); });
} }
function hasTransparency(info) { function hasTransparency(image) {
var pixels = info.decoded; var pixels = image.decoded;
var pixelsLength = info.width * info.height; var pixelsLength = image.width * image.height;
for (var i = 0; i < pixelsLength; ++i) { for (var i = 0; i < pixelsLength; ++i) {
if (pixels[i * 4 + 3] < 255) { if (pixels[i * 4 + 3] < 255) {
return true; return true;
@ -89,35 +89,34 @@ function parsePng(data) {
}); });
} }
function getPngInfo(data, info, options) { function decodePng(image, options) {
// Color type is encoded in the 25th bit of the png // Color type is encoded in the 25th bit of the png
var colorType = data[25]; var source = image.source;
var colorType = source[25];
var channels = getChannels(colorType); var channels = getChannels(colorType);
var checkTransparency = (channels === 4 && options.checkTransparency); var checkTransparency = (channels === 4 && options.checkTransparency);
var decode = options.decode || checkTransparency; var decode = options.decode || checkTransparency;
if (decode) { if (decode) {
return parsePng(data) return parsePng(source)
.then(function(decodedResults) { .then(function(decodedResults) {
info.decoded = decodedResults.data; image.decoded = decodedResults.data;
info.width = decodedResults.width; image.width = decodedResults.width;
info.height = decodedResults.height; image.height = decodedResults.height;
if (checkTransparency) { if (checkTransparency) {
info.transparent = hasTransparency(info); image.transparent = hasTransparency(image);
} }
return info;
}); });
} }
return info;
} }
function getJpegInfo(data, info, options) { function decodeJpeg(image, options) {
if (options.decode) { if (options.decode) {
var decodedResults = jpeg.decode(data); var source = image.source;
info.decoded = decodedResults.data; var decodedResults = jpeg.decode(source);
info.width = decodedResults.width; image.decoded = decodedResults.data;
info.height = decodedResults.height; image.width = decodedResults.width;
image.height = decodedResults.height;
} }
return info;
} }

View File

@ -11,7 +11,7 @@ module.exports = loadMtl;
* @param {String} mtlPath Path to the mtl file. * @param {String} mtlPath Path to the mtl file.
* @param {Object} options An object with the following properties: * @param {Object} options An object with the following properties:
* @param {Boolean} options.metallicRoughness The values in the mtl file are already metallic-roughness PBR values and no conversion step should be applied. Metallic is stored in the Ks and map_Ks slots and roughness is stored in the Ns and map_Ns slots. * @param {Boolean} options.metallicRoughness The values in the mtl file are already metallic-roughness PBR values and no conversion step should be applied. Metallic is stored in the Ks and map_Ks slots and roughness is stored in the Ns and map_Ns slots.
* @returns {Promise} A promise resolving to the materials. * @returns {Promise} A promise resolving to an array of materials.
* *
* @private * @private
*/ */

View File

@ -32,12 +32,13 @@ module.exports = obj2gltf;
* @param {Boolean} [options.metallicRoughness=false] The values in the mtl file are already metallic-roughness PBR values and no conversion step should be applied. Metallic is stored in the Ks and map_Ks slots and roughness is stored in the Ns and map_Ns slots. * @param {Boolean} [options.metallicRoughness=false] The values in the mtl file are already metallic-roughness PBR values and no conversion step should be applied. Metallic is stored in the Ks and map_Ks slots and roughness is stored in the Ns and map_Ns slots.
* @param {Boolean} [options.specularGlossiness=false] The values in the mtl file are already specular-glossiness PBR values and no conversion step should be applied. Specular is stored in the Ks and map_Ks slots and glossiness is stored in the Ns and map_Ns slots. The glTF will be saved with the KHR_materials_pbrSpecularGlossiness extension. * @param {Boolean} [options.specularGlossiness=false] The values in the mtl file are already specular-glossiness PBR values and no conversion step should be applied. Specular is stored in the Ks and map_Ks slots and glossiness is stored in the Ns and map_Ns slots. The glTF will be saved with the KHR_materials_pbrSpecularGlossiness extension.
* @param {Boolean} [options.materialsCommon=false] The glTF will be saved with the KHR_materials_common extension. * @param {Boolean} [options.materialsCommon=false] The glTF will be saved with the KHR_materials_common extension.
* @param {String} [options.metallicRoughnessOcclusionTexture] Path to the metallic-roughness-occlusion texture used by the model, where occlusion is stored in the red channel, roughness is stored in the green channel, and metallic is stored in the blue channel. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. The model will be saved with a pbrMetallicRoughness material. * @param {Object} [options.overridingImages] An object containing image paths that override material values defined in the .mtl file. This is often convenient in workflows where the .mtl does not exist or is not set up to use PBR materials. Intended for models with a single material.
* @param {String} [options.specularGlossinessTexture] Path to the specular-glossiness texture used by the model, where specular color is stored in the red, green, and blue channels and specular glossiness is stored in the alpha channel. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. The model will be saved with a material using the KHR_materials_pbrSpecularGlossiness extension. * @param {String} [options.overridingImages.metallicRoughnessOcclusionTexture] Path to the metallic-roughness-occlusion texture, where occlusion is stored in the red channel, roughness is stored in the green channel, and metallic is stored in the blue channel. The model will be saved with a pbrMetallicRoughness material.
* @param {String} [options.occlusionTexture] Path to the occlusion texture used by the model. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. Ignored if metallicRoughnessOcclusionTexture is also set. * @param {String} [options.overridingImages.specularGlossinessTexture] Path to the specular-glossiness texture, where specular color is stored in the red, green, and blue channels and specular glossiness is stored in the alpha channel. The model will be saved with a material using the KHR_materials_pbrSpecularGlossiness extension.
* @param {String} [options.normalTexture] Path to the normal texture used by the model. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. * @param {String} [options.overridingImages.occlusionTexture] Path to the occlusion texture. Ignored if metallicRoughnessOcclusionTexture is also set.
* @param {String} [options.baseColorTexture] Path to the baseColor/diffuse texture used by the model. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. * @param {String} [options.overridingImages.normalTexture] Path to the normal texture.
* @param {String} [options.emissiveTexture] Path to the emissive texture used by the model. This may be used instead of setting texture paths in the .mtl file, and is intended for models that use one material. * @param {String} [options.overridingImages.baseColorTexture] Path to the baseColor/diffuse texture.
* @param {String} [options.overridingImages.emissiveTexture] Path to the emissive texture.
* @param {Logger} [options.logger] A callback function for handling logged messages. Defaults to console.log. * @param {Logger} [options.logger] A callback function for handling logged messages. Defaults to console.log.
* @return {Promise} A promise that resolves when the glTF file is saved. * @return {Promise} A promise that resolves when the glTF file is saved.
@ -57,6 +58,7 @@ function obj2gltf(objPath, gltfPath, options) {
var metallicRoughness = defaultValue(options.metallicRoughness, defaults.metallicRoughness); var metallicRoughness = defaultValue(options.metallicRoughness, defaults.metallicRoughness);
var specularGlossiness = defaultValue(options.specularGlossiness, defaults.specularGlossiness); var specularGlossiness = defaultValue(options.specularGlossiness, defaults.specularGlossiness);
var materialsCommon = defaultValue(options.materialsCommon, defaults.materialsCommon); var materialsCommon = defaultValue(options.materialsCommon, defaults.materialsCommon);
var overridingImages = defaultValue(options.overridingImages, defaultValue.EMPTY_OBJECT);
var logger = defaultValue(options.logger, defaults.logger); var logger = defaultValue(options.logger, defaults.logger);
options.separate = separate; options.separate = separate;
@ -69,6 +71,7 @@ function obj2gltf(objPath, gltfPath, options) {
options.metallicRoughness = metallicRoughness; options.metallicRoughness = metallicRoughness;
options.specularGlossiness = specularGlossiness; options.specularGlossiness = specularGlossiness;
options.materialsCommon = materialsCommon; options.materialsCommon = materialsCommon;
options.overridingImages = overridingImages;
options.logger = logger; options.logger = logger;
if (!defined(objPath)) { if (!defined(objPath)) {
@ -83,17 +86,17 @@ function obj2gltf(objPath, gltfPath, options) {
throw new DeveloperError('Only one material type may be set from [--metallicRoughness, --specularGlossiness, --materialsCommon].'); throw new DeveloperError('Only one material type may be set from [--metallicRoughness, --specularGlossiness, --materialsCommon].');
} }
if (defined(options.metallicRoughnessOcclusionTexture) && defined(options.specularGlossinessTexture)) { if (defined(overridingImages.metallicRoughnessOcclusionTexture) && defined(overridingImages.specularGlossinessTexture)) {
throw new DeveloperError('options.metallicRoughnessOcclusionTexture and options.specularGlossinessTexture cannot both be defined.'); throw new DeveloperError('options.overridingImages.metallicRoughnessOcclusionTexture and options.overridingImages.specularGlossinessTexture cannot both be defined.');
} }
if (defined(options.metallicRoughnessOcclusionTexture)) { if (defined(overridingImages.metallicRoughnessOcclusionTexture)) {
options.metallicRoughness = true; options.metallicRoughness = true;
options.specularGlossiness = false; options.specularGlossiness = false;
options.materialsCommon = false; options.materialsCommon = false;
} }
if (defined(options.specularGlossinessTexture)) { if (defined(overridingImages.specularGlossinessTexture)) {
options.metallicRoughness = false; options.metallicRoughness = false;
options.specularGlossiness = true; options.specularGlossiness = true;
options.materialsCommon = false; options.materialsCommon = false;
@ -131,18 +134,32 @@ function obj2gltf(objPath, gltfPath, options) {
} }
function loadOverridingImages(options) { function loadOverridingImages(options) {
// The texture paths supplied in the .mtl may be overriden by the texture path supplied in options var overridingImages = options.overridingImages;
var checkTransparencyOptions = { var promises = [];
checkTransparency : options.checkTransparency for (var imageName in overridingImages) {
}; if (overridingImages.hasOwnProperty(imageName)) {
var imagePaths = [options.metallicRoughnessOcclusionTexture, options.specularGlossinessTexture, options.occlusionTexture, options.normalTexture, options.baseColorTexture, options.emissiveTexture]; promises.push(loadOverridingImage(imageName, overridingImages, options));
imagePaths = imagePaths.filter(function(imagePath) {return defined(imagePath);}); }
return Promise.map(imagePaths, function(imagePath) { }
var imageOptions = (imagePath === options.baseColorTexture) ? checkTransparencyOptions : undefined; return Promise.all(promises);
return loadImage(imagePath, imageOptions); }
}).then(function(images) {
options.overridingImages = images; function loadOverridingImage(imageName, overridingImages, options) {
}); var imagePath = overridingImages[imageName];
var imageOptions;
if (imageName === 'baseColorTexture') {
imageOptions = {
checkTransparency : options.checkTransparency
};
}
return loadImage(imagePath, imageOptions)
.then(function(image) {
overridingImages[imageName] = image;
})
.catch(function() {
delete overridingImages[imageName];
options.logger('Could not read image file at ' + imagePath + '. This image will be ignored.');
});
} }
/** /**

View File

@ -21,7 +21,7 @@ var metallicTextureUrl = 'specs/data/box-complex-material/specular.jpeg';
var roughnessTextureUrl = 'specs/data/box-complex-material/shininess.png'; var roughnessTextureUrl = 'specs/data/box-complex-material/shininess.png';
var defaultOptions = clone(obj2gltf.defaults); var defaultOptions = clone(obj2gltf.defaults);
defaultOptions.overridingImages = []; defaultOptions.overridingImages = {};
var checkTransparencyOptions = clone(defaultOptions); var checkTransparencyOptions = clone(defaultOptions);
checkTransparencyOptions.checkTransparency = true; checkTransparencyOptions.checkTransparency = true;
var decodeOptions = clone(defaultOptions); var decodeOptions = clone(defaultOptions);

View File

@ -11,66 +11,66 @@ var transparentImage = 'specs/data/box-complex-material/diffuse.png';
describe('loadImage', function() { describe('loadImage', function() {
it('loads png image', function(done) { it('loads png image', function(done) {
expect(loadImage(pngImage) expect(loadImage(pngImage)
.then(function(info) { .then(function(image) {
expect(info.transparent).toBe(false); expect(image.transparent).toBe(false);
expect(info.source).toBeDefined(); expect(image.source).toBeDefined();
expect(info.extension).toBe('.png'); expect(image.extension).toBe('.png');
expect(info.path).toBe(pngImage); expect(image.path).toBe(pngImage);
expect(info.decoded).toBeUndefined(); expect(image.decoded).toBeUndefined();
expect(info.width).toBeUndefined(); expect(image.width).toBeUndefined();
expect(info.height).toBeUndefined(); expect(image.height).toBeUndefined();
}), done).toResolve(); }), done).toResolve();
}); });
it('loads jpg image', function(done) { it('loads jpg image', function(done) {
expect(loadImage(jpgImage) expect(loadImage(jpgImage)
.then(function(info) { .then(function(image) {
expect(info.transparent).toBe(false); expect(image.transparent).toBe(false);
expect(info.source).toBeDefined(); expect(image.source).toBeDefined();
expect(info.extension).toBe('.jpg'); expect(image.extension).toBe('.jpg');
expect(info.decoded).toBeUndefined(); expect(image.decoded).toBeUndefined();
expect(info.width).toBeUndefined(); expect(image.width).toBeUndefined();
expect(info.height).toBeUndefined(); expect(image.height).toBeUndefined();
}), done).toResolve(); }), done).toResolve();
}); });
it('loads jpeg image', function(done) { it('loads jpeg image', function(done) {
expect(loadImage(jpegImage) expect(loadImage(jpegImage)
.then(function(info) { .then(function(image) {
expect(info.transparent).toBe(false); expect(image.transparent).toBe(false);
expect(info.source).toBeDefined(); expect(image.source).toBeDefined();
expect(info.extension).toBe('.jpeg'); expect(image.extension).toBe('.jpeg');
expect(info.decoded).toBeUndefined(); expect(image.decoded).toBeUndefined();
expect(info.width).toBeUndefined(); expect(image.width).toBeUndefined();
expect(info.height).toBeUndefined(); expect(image.height).toBeUndefined();
}), done).toResolve(); }), done).toResolve();
}); });
it('loads gif image', function(done) { it('loads gif image', function(done) {
expect(loadImage(gifImage) expect(loadImage(gifImage)
.then(function(info) { .then(function(image) {
expect(info.transparent).toBe(false); expect(image.transparent).toBe(false);
expect(info.source).toBeDefined(); expect(image.source).toBeDefined();
expect(info.extension).toBe('.gif'); expect(image.extension).toBe('.gif');
expect(info.decoded).toBeUndefined(); expect(image.decoded).toBeUndefined();
expect(info.width).toBeUndefined(); expect(image.width).toBeUndefined();
expect(info.height).toBeUndefined(); expect(image.height).toBeUndefined();
}), done).toResolve(); }), done).toResolve();
}); });
it('loads grayscale image', function(done) { it('loads grayscale image', function(done) {
expect(loadImage(grayscaleImage) expect(loadImage(grayscaleImage)
.then(function(info) { .then(function(image) {
expect(info.transparent).toBe(false); expect(image.transparent).toBe(false);
expect(info.source).toBeDefined(); expect(image.source).toBeDefined();
expect(info.extension).toBe('.png'); expect(image.extension).toBe('.png');
}), done).toResolve(); }), done).toResolve();
}); });
it('loads image with alpha channel', function(done) { it('loads image with alpha channel', function(done) {
expect(loadImage(transparentImage) expect(loadImage(transparentImage)
.then(function(info) { .then(function(image) {
expect(info.transparent).toBe(false); expect(image.transparent).toBe(false);
}), done).toResolve(); }), done).toResolve();
}); });
@ -80,8 +80,8 @@ describe('loadImage', function() {
}; };
expect(loadImage(transparentImage, options) expect(loadImage(transparentImage, options)
.then(function(info) { .then(function(image) {
expect(info.transparent).toBe(true); expect(image.transparent).toBe(true);
}), done).toResolve(); }), done).toResolve();
}); });
@ -91,10 +91,10 @@ describe('loadImage', function() {
}; };
expect(loadImage(pngImage, options) expect(loadImage(pngImage, options)
.then(function(info) { .then(function(image) {
expect(info.decoded).toBeDefined(); expect(image.decoded).toBeDefined();
expect(info.width).toBe(211); expect(image.width).toBe(211);
expect(info.height).toBe(211); expect(image.height).toBe(211);
}), done).toResolve(); }), done).toResolve();
}); });
@ -104,10 +104,10 @@ describe('loadImage', function() {
}; };
expect(loadImage(jpegImage, options) expect(loadImage(jpegImage, options)
.then(function(info) { .then(function(image) {
expect(info.decoded).toBeDefined(); expect(image.decoded).toBeDefined();
expect(info.width).toBe(211); expect(image.width).toBe(211);
expect(info.height).toBe(211); expect(image.height).toBe(211);
}), done).toResolve(); }), done).toResolve();
}); });
}); });

View File

@ -9,6 +9,10 @@ var gltfPath = 'specs/data/box-textured/box-textured.gltf';
var glbPath = 'specs/data/box-textured/box-textured.glb'; var glbPath = 'specs/data/box-textured/box-textured.glb';
var objPathNonExistent = 'specs/data/non-existent.obj'; var objPathNonExistent = 'specs/data/non-existent.obj';
var complexMaterialObjPath = 'specs/data/box-complex-material/box-complex-material.obj';
var complexMaterialGltfPath = 'specs/data/box-complex-material/box-complex-material.gltf';
var textureUrl = 'specs/data/box-textured/cesium.png';
describe('obj2gltf', function() { describe('obj2gltf', function() {
beforeEach(function() { beforeEach(function() {
spyOn(fsExtra, 'outputJson').and.returnValue(Promise.resolve()); spyOn(fsExtra, 'outputJson').and.returnValue(Promise.resolve());
@ -66,6 +70,26 @@ describe('obj2gltf', function() {
}), done).toResolve(); }), done).toResolve();
}); });
it('sets overriding images', function(done) {
var options = {
overridingImages : {
metallicRoughnessOcclusionTexture : textureUrl,
normalTexture : textureUrl,
baseColorTexture : textureUrl,
emissiveTexture : textureUrl
},
separateTextures : true
};
expect(obj2gltf(complexMaterialObjPath, complexMaterialGltfPath, options)
.then(function() {
var args = fsExtra.outputFile.calls.allArgs();
var length = args.length;
for (var i = 0; i < length; ++i) {
expect(path.basename(args[i][0])).toBe(path.basename(textureUrl));
}
}), done).toResolve();
});
it('rejects if obj path does not exist', function(done) { it('rejects if obj path does not exist', function(done) {
expect(obj2gltf(objPathNonExistent, gltfPath), done).toRejectWith(Error); expect(obj2gltf(objPathNonExistent, gltfPath), done).toRejectWith(Error);
}); });