diff --git a/lib/updateVersion.js b/lib/updateVersion.js index 0b7110aa..d71392d4 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -1084,6 +1084,26 @@ function convertTechniquesToPbr(gltf, options) { removeExtension(gltf, "KHR_blend"); } +function assignAsBaseColor(material, baseColor) { + if (defined(baseColor)) { + if (isVec4(baseColor)) { + material.pbrMetallicRoughness.baseColorFactor = srgbToLinear(baseColor); + } else if (isTexture(baseColor)) { + material.pbrMetallicRoughness.baseColorTexture = baseColor; + } + } +} + +function assignAsEmissive(material, emissive) { + if (defined(emissive)) { + if (isVec4(emissive)) { + material.emissiveFactor = emissive.slice(0, 3); + } else if (isTexture(emissive)) { + material.emissiveTexture = emissive; + } + } +} + function convertMaterialsCommonToPbr(gltf) { // Future work: convert KHR_materials_common lights to KHR_lights_punctual ForEach.material(gltf, function (material) { @@ -1091,80 +1111,61 @@ function convertMaterialsCommonToPbr(gltf) { material.extensions, defaultValue.EMPTY_OBJECT, ).KHR_materials_common; + if (!defined(materialsCommon)) { + // Nothing to do + return; + } - if (defined(materialsCommon)) { - const technique = materialsCommon.technique; - if (technique === "CONSTANT") { - // Add the KHR_materials_unlit extension - addExtensionsUsed(gltf, "KHR_materials_unlit"); - material.extensions = defined(material.extensions) - ? material.extensions - : {}; - material.extensions["KHR_materials_unlit"] = {}; - } - - const values = defined(materialsCommon.values) - ? materialsCommon.values + const values = defaultValue(materialsCommon.values, {}); + const ambient = values.ambient; + const diffuse = values.diffuse; + const emission = values.emission; + const transparency = values.transparency; + + // These actually exist on the extension object, not the values object despite what's shown in the spec + const doubleSided = materialsCommon.doubleSided; + const transparent = materialsCommon.transparent; + + // Ignore specular and shininess for now because the conversion to PBR + // isn't straightforward and depends on the technique + initializePbrMaterial(material); + + const technique = materialsCommon.technique; + if (technique === "CONSTANT") { + // Add the KHR_materials_unlit extension + addExtensionsUsed(gltf, "KHR_materials_unlit"); + material.extensions = defined(material.extensions) + ? material.extensions : {}; + material.extensions["KHR_materials_unlit"] = {}; - const ambient = values.ambient; - const diffuse = values.diffuse; - const emission = values.emission; - const transparency = values.transparency; - - // These actually exist on the extension object, not the values object despite what's shown in the spec - const doubleSided = materialsCommon.doubleSided; - const transparent = materialsCommon.transparent; - - // Ignore specular and shininess for now because the conversion to PBR - // isn't straightforward and depends on the technique - initializePbrMaterial(material); - - if (defined(ambient)) { - if (isVec4(ambient)) { - material.emissiveFactor = ambient.slice(0, 3); - } else if (isTexture(ambient)) { - material.emissiveTexture = ambient; - } - } - - if (defined(diffuse)) { - if (isVec4(diffuse)) { - material.pbrMetallicRoughness.baseColorFactor = srgbToLinear(diffuse); - } else if (isTexture(diffuse)) { - material.pbrMetallicRoughness.baseColorTexture = diffuse; - } - } - - if (defined(doubleSided)) { - material.doubleSided = doubleSided; - } - - if (defined(emission)) { - if (isVec4(emission)) { - material.emissiveFactor = emission.slice(0, 3); - } else if (isTexture(emission)) { - material.emissiveTexture = emission; - } - } - - if (defined(transparency)) { - if (defined(material.pbrMetallicRoughness.baseColorFactor)) { - material.pbrMetallicRoughness.baseColorFactor[3] *= transparency; - } else { - material.pbrMetallicRoughness.baseColorFactor = [ - 1, - 1, - 1, - transparency, - ]; - } - } + // The CONSTANT technique does not support 'diffuse', so + // assign either the 'emission' or the 'ambient' as the + // base color + assignAsBaseColor(material, emission); + assignAsBaseColor(material, ambient); + } else { + // Assign the 'diffuse' as the base color, and + // the 'ambient' or 'emissive' as the emissive + // part if they are present. + assignAsBaseColor(material, diffuse); + assignAsEmissive(material, ambient); + assignAsEmissive(material, emission); + } - if (defined(transparent)) { - material.alphaMode = transparent ? "BLEND" : "OPAQUE"; + if (defined(doubleSided)) { + material.doubleSided = doubleSided; + } + if (defined(transparency)) { + if (defined(material.pbrMetallicRoughness.baseColorFactor)) { + material.pbrMetallicRoughness.baseColorFactor[3] *= transparency; + } else { + material.pbrMetallicRoughness.baseColorFactor = [1, 1, 1, transparency]; } } + if (defined(transparent)) { + material.alphaMode = transparent ? "BLEND" : "OPAQUE"; + } }); removeExtension(gltf, "KHR_materials_common"); diff --git a/specs/lib/updateVersionSpec.js b/specs/lib/updateVersionSpec.js index 4b68e329..fbe7d26b 100644 --- a/specs/lib/updateVersionSpec.js +++ b/specs/lib/updateVersionSpec.js @@ -888,6 +888,27 @@ describe("updateVersion", () => { expect(gltf.extensionsUsed.indexOf("KHR_materials_unlit") !== -1); }); + it("updates glTF 1.0 with KHR_materials_common with CONSTANT technique to PBR materials using emissive as the base color texture when diffuse is not present", async () => { + const gltf = fsExtra.readJsonSync(gltf1MaterialsCommonTextured); + await readResources(gltf, { + resourceDirectory: path.dirname(gltf1MaterialsCommonTextured), + }); + + const materialsCommon = + gltf.materials["Effect-Texture"].extensions.KHR_materials_common; + // Move the 'diffuse' texture definition into 'emission', and expect + // this to show up as the base color texture after the update + materialsCommon.values.emission = materialsCommon.values.diffuse; + delete materialsCommon.values.diffuse; + materialsCommon.technique = "CONSTANT"; + updateVersion(gltf); + + const material = gltf.materials[0]; + expect(material.pbrMetallicRoughness.baseColorTexture).toBeDefined(); + expect(material.extensions.KHR_materials_unlit).toBeDefined(); + expect(gltf.extensionsUsed.indexOf("KHR_materials_unlit") !== -1); + }); + it("updates glTF 1.0 with KHR_materials_common with other values to PBR materials", async () => { const gltf = fsExtra.readJsonSync(gltf1MaterialsCommon); await readResources(gltf, {