From 44e9d5fa3b693d270a03e14b8682eb3c32fb58dd Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Thu, 4 May 2017 15:39:01 -0400 Subject: [PATCH] Add back KHR_materials_common --- README.md | 5 ++- bin/obj2gltf.js | 17 +++++--- lib/createGltf.js | 105 +++++++++++++++++++++++++++++++++++++++------- lib/obj2gltf.js | 29 ++++++++----- 4 files changed, 123 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index aa209af..df14f49 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,9 @@ Using obj2gltf as a command-line tool: |`--inputUpAxis`|Up axis of the obj. Choices are 'X', 'Y', and 'Z'.|No, default `Y`| |`--outputUpAxis`|Up axis of the converted glTF. Choices are 'X', 'Y', and 'Z'.|No, default `Y`| |`--packOcclusion`|Pack the occlusion texture in the red channel of metallic-roughness texture.|No, default `false`| -|`--inputMetallicRoughness`|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.|No, default `false`| -|`--inputSpecularGlossiness`|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.|No, default `false`| +|`--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.|No, default `false`| +|`--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.|No, default `false`| +|`--materialsCommon`|The glTF will be saved with the KHR_materials_common extension.|No, default `false`| ## Build Instructions diff --git a/bin/obj2gltf.js b/bin/obj2gltf.js index 24b6311..1eb8262 100644 --- a/bin/obj2gltf.js +++ b/bin/obj2gltf.js @@ -108,15 +108,20 @@ var argv = yargs type: 'boolean', default: defaults.packOcclusion }, - inputMetallicRoughness : { + metallicRoughness : { describe: '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.', type: 'boolean', - default : defaults.metallicRoughness + default: defaults.metallicRoughness }, - inputSpecularGlossiness : { + specularGlossiness : { describe: '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.', type: 'boolean', - default : defaults.specularGlossiness + default: defaults.specularGlossiness + }, + materialsCommon : { + describe: 'The glTF will be saved with the KHR_materials_common extension.', + type: 'boolean', + default: defaults.materialsCommon } }).parse(args); @@ -144,8 +149,8 @@ var options = { inputUpAxis : argv.inputUpAxis, outputUpAxis : argv.outputUpAxis, packOcclusion : argv.packOcclusion, - inputMetallicRoughness : argv.inputMetallicRoughness, - inputSpecularGlossiness : argv.inputSpecularGlossiness + metallicRoughness : argv.metallicRoughness, + specularGlossiness : argv.specularGlossiness }; console.time('Total'); diff --git a/lib/createGltf.js b/lib/createGltf.js index fa01216..a568c4f 100644 --- a/lib/createGltf.js +++ b/lib/createGltf.js @@ -5,6 +5,7 @@ var PNG = require('pngjs').PNG; var Material = require('./Material'); var CesiumMath = Cesium.Math; +var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; var WebGLConstants = Cesium.WebGLConstants; @@ -15,9 +16,10 @@ module.exports = createGltf; * * @param {Object} objData Output of obj.js, containing an array of nodes containing geometry information, materials, and images. * @param {Object} options An object with the following properties: - * @param {Boolean} [options.packOcclusion=false] Pack the occlusion texture in the red channel of metallic-roughness texture. - * @param {Boolean} [options.inputMetallicRoughness=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.inputSpecularGlossiness=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.packOcclusion] Pack the occlusion texture in the red channel of metallic-roughness texture. + * @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.materialsCommon] The glTF will be saved with the KHR_materials_common extension. * @param {Boolean} options.logger A callback function for handling logged messages. Defaults to console.log. * @returns {Object} A glTF asset. * @@ -33,6 +35,8 @@ function createGltf(objData, options) { asset : {}, buffers : [], bufferViews : [], + extensionsUsed : [], + extensionsRequired : [], images : [], materials : [], meshes : [], @@ -486,7 +490,10 @@ function createSpecularGlossinessMaterial(gltf, images, material, options) { var doubleSided = transparent; var alphaMode = transparent ? 'BLEND' : 'OPAQUE'; - var gltfMaterial = { + gltf.extensionsUsed.push('KHR_materials_pbrSpecularGlossiness'); + gltf.extensionsRequired.push('KHR_materials_pbrSpecularGlossiness'); + + return { name : materialName, extensions : { KHR_materials_pbrSpecularGlossiness: { @@ -504,8 +511,6 @@ function createSpecularGlossinessMaterial(gltf, images, material, options) { alphaMode : alphaMode, doubleSided : doubleSided }; - - return gltfMaterial; } function createMetallicRoughnessMaterial(gltf, images, material, options) { @@ -558,7 +563,7 @@ function createMetallicRoughnessMaterial(gltf, images, material, options) { var doubleSided = transparent; var alphaMode = transparent ? 'BLEND' : 'OPAQUE'; - var gltfMaterial = { + return { name : materialName, pbrMetallicRoughness : { baseColorTexture : baseColorTexture, @@ -574,14 +579,13 @@ function createMetallicRoughnessMaterial(gltf, images, material, options) { alphaMode : alphaMode, doubleSided : doubleSided }; - - return gltfMaterial; } function convertTraditionalToMetallicRoughness(material) { // Translate the blinn-phong model to the pbr metallic-roughness model // Roughness factor is a combination of specular intensity and shininess // Metallic factor is 0.0 + // This does not convert textures var specularIntensity = material.specularColor[0]; var specularShininess = material.specularShininess; @@ -602,12 +606,83 @@ function convertTraditionalToMetallicRoughness(material) { material.specularShiness = roughnessFactor; } -function addMaterial(gltf, images, material, options) { +function createMaterialsCommonMaterial(gltf, images, material, hasNormals, options) { + var materialName = material.name; + + var ambientImage = getImage(images, material.ambientTexture); + var diffuseImage = getImage(images, material.diffuseTexture); + var emissiveImage = getImage(images, material.emissiveTexture); + var specularImage = getImage(images, material.specularTexture); + + var ambient = defaultValue(getTexture(gltf, ambientImage), material.ambientColor); + var diffuse = defaultValue(getTexture(gltf, diffuseImage), material.diffuseColor); + var emission = defaultValue(getTexture(gltf, emissiveImage), material.emissiveColor); + var specular = defaultValue(getTexture(gltf, specularImage), material.specularColor); + + var alpha = material.alpha; + var shininess = material.specularShininess; + var hasSpecular = (shininess > 0.0) && (specular[0] > 0.0 || specular[1] > 0.0 || specular[2] > 0.0); + + var transparent; + var transparency = 1.0; + if (defined(diffuseImage)) { + transparency = alpha; + transparent = diffuseImage.transparent || (transparency < 1.0); + } else { + diffuse[3] = alpha; + transparent = alpha < 1.0; + } + + if (!defined(ambientImage)) { + // If ambient color is [1, 1, 1] assume it is a multiplier and instead change to [0, 0, 0] + if (ambient[0] === 1.0 && ambient[1] === 1.0 && ambient[2] === 1.0) { + ambient = [0.0, 0.0, 0.0, 1.0]; + } + } + + var doubleSided = transparent; + + if (!hasNormals) { + // Constant technique only factors in ambient and emission sources - set emission to diffuse + emission = diffuse; + diffuse = [0, 0, 0, 1]; + } + + var technique = hasNormals ? (hasSpecular ? 'PHONG' : 'LAMBERT') : 'CONSTANT'; + + gltf.extensionsUsed.push('KHR_materials_common'); + gltf.extensionsRequired.push('KHR_materials_common'); + + return { + name : materialName, + extensions : { + KHR_materials_common : { + technique : technique, + transparent : transparent, + doubleSided : doubleSided, + values : { + ambient : ambient, + diffuse : diffuse, + emission : emission, + specular : specular, + shininess : shininess, + transparency : transparency, + transparent : transparent, + doubleSided : doubleSided + } + } + } + }; +} + +function addMaterial(gltf, images, material, hasNormals, options) { var gltfMaterial; - if (options.inputSpecularGlossiness) { + if (options.specularGlossiness) { gltfMaterial = createSpecularGlossinessMaterial(gltf, images, material, options); - } else if (options.inputMetallicRoughness) { + } else if (options.metallicRoughness) { gltfMaterial = createMetallicRoughnessMaterial(gltf, images, material, options); + } else if (options.materialsCommon) { + gltfMaterial = createMaterialsCommonMaterial(gltf, images, material, hasNormals, options); } else { convertTraditionalToMetallicRoughness(material); gltfMaterial = createMetallicRoughnessMaterial(gltf, images, material, options); @@ -629,7 +704,7 @@ function getMaterialIndex(gltf, materialName) { return undefined; } -function getMaterial(gltf, materials, images, materialName, options) { +function getMaterial(gltf, materials, images, materialName, hasNormals, options) { if (!defined(materialName)) { // Create a default material if the primitive does not specify one materialName = 'default'; @@ -651,7 +726,7 @@ function getMaterial(gltf, materials, images, materialName, options) { var materialIndex = getMaterialIndex(gltf, materialName); if (!defined(materialIndex)) { - materialIndex = addMaterial(gltf, images, material, options); + materialIndex = addMaterial(gltf, images, material, hasNormals, options); } return materialIndex; @@ -750,7 +825,7 @@ function addMesh(gltf, materials, images, bufferState, uint32Indices, mesh, opti var indexAccessorIndex = addIndexArray(gltf, bufferState, primitive.indices, uint32Indices); primitive.indices = undefined; // Unload resources - var materialIndex = getMaterial(gltf, materials, images, primitive.material, options); + var materialIndex = getMaterial(gltf, materials, images, primitive.material, hasNormals, options); gltfPrimitives.push({ attributes : attributes, diff --git a/lib/obj2gltf.js b/lib/obj2gltf.js index 1ed7fe4..a7bb46b 100644 --- a/lib/obj2gltf.js +++ b/lib/obj2gltf.js @@ -40,8 +40,9 @@ module.exports = obj2gltf; * @param {String} [options.inputUpAxis='Y'] Up axis of the obj. Choices are 'X', 'Y', and 'Z'. * @param {String} [options.outputUpAxis='Y'] Up axis of the converted glTF. Choices are 'X', 'Y', and 'Z'. * @param {Boolean} [options.packOcclusion=false] Pack the occlusion texture in the red channel of metallic-roughness texture. - * @param {Boolean} [options.inputMetallicRoughness=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.inputSpecularGlossiness=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.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.materialsCommon=false] The glTF will be saved with the KHR_materials_common extension. * @param {Logger} [options.logger] A callback function for handling logged messages. Defaults to console.log. */ function obj2gltf(objPath, gltfPath, options) { @@ -63,8 +64,9 @@ function obj2gltf(objPath, gltfPath, options) { var inputUpAxis = defaultValue(options.inputUpAxis, defaults.inputUpAxis); var outputUpAxis = defaultValue(options.outputUpAxis, defaults.outputUpAxis); var packOcclusion = defaultValue(options.packOcclusion, defaults.packOcclusion); - var inputMetallicRoughness = defaultValue(options.inputMetallicRoughness, defaults.inputMetallicRoughness); - var inputSpecularGlossiness = defaultValue(options.inputSpecularGlossiness, defaults.inputSpecularGlossiness); + var metallicRoughness = defaultValue(options.metallicRoughness, defaults.metallicRoughness); + var specularGlossiness = defaultValue(options.specularGlossiness, defaults.specularGlossiness); + var materialsCommon = defaultValue(options.materialsCommon, defaults.materialsCommon); var logger = defaultValue(options.logger, defaults.logger); options.separate = separate; @@ -74,8 +76,9 @@ function obj2gltf(objPath, gltfPath, options) { options.inputUpAxis = inputUpAxis; options.outputUpAxis = outputUpAxis; options.packOcclusion = packOcclusion; - options.inputMetallicRoughness = inputMetallicRoughness; - options.inputSpecularGlossiness = inputSpecularGlossiness; + options.metallicRoughness = metallicRoughness; + options.specularGlossiness = specularGlossiness; + options.materialsCommon = materialsCommon; options.logger = logger; if (!defined(objPath)) { @@ -96,8 +99,8 @@ function obj2gltf(objPath, gltfPath, options) { return Promise.reject(new RuntimeError('--bypassPipeline does not convert to binary glTF')); } - if (inputMetallicRoughness && inputSpecularGlossiness) { - throw new DeveloperError('--inputMetallicRoughness and --inputSpecularGlossiness cannot both be set.'); + if (metallicRoughness + specularGlossiness + materialsCommon > 1) { + throw new DeveloperError('Only one material type may be set from [--metallicRoughness, --specularGlossiness, --materialsCommon].'); } gltfPath = path.join(path.dirname(gltfPath), modelName + extension); @@ -243,13 +246,19 @@ obj2gltf.defaults = { * @type Boolean * @default false */ - inputMetallicRoughness: false, + metallicRoughness: 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. * @type Boolean * @default false */ - inputSpecularGlossiness: false, + 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. + * @type Boolean + * @default false + */ + materialsCommon: false, /** * @private