|
@@ -15,6 +15,8 @@ module BABYLON.GLTF2 {
|
|
|
*/
|
|
|
private static maxSpecularPower = 1024;
|
|
|
|
|
|
+ private static epsilon = 1e-6;
|
|
|
+
|
|
|
/**
|
|
|
* Gets the materials from a Babylon scene and converts them to glTF materials.
|
|
|
* @param scene
|
|
@@ -34,7 +36,56 @@ module BABYLON.GLTF2 {
|
|
|
else if (babylonMaterial instanceof PBRMetallicRoughnessMaterial) {
|
|
|
_GLTFMaterial.ConvertPBRMetallicRoughnessMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
|
|
|
}
|
|
|
+ else if (babylonMaterial instanceof PBRMaterial) {
|
|
|
+ _GLTFMaterial.ConvertPBRMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Tools.Error("Unsupported material type: " + babylonMaterial.name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Makes a copy of the glTF material without the texture parameters.
|
|
|
+ * @param originalMaterial - original glTF material.
|
|
|
+ * @returns glTF material without texture parameters
|
|
|
+ */
|
|
|
+ public static StripTexturesFromMaterial(originalMaterial: IMaterial): IMaterial {
|
|
|
+ let newMaterial: IMaterial = {};
|
|
|
+ if (originalMaterial) {
|
|
|
+ newMaterial.name = originalMaterial.name;
|
|
|
+ newMaterial.doubleSided = originalMaterial.doubleSided;
|
|
|
+ newMaterial.alphaMode = originalMaterial.alphaMode;
|
|
|
+ newMaterial.alphaCutoff = originalMaterial.alphaCutoff;
|
|
|
+ newMaterial.emissiveFactor = originalMaterial.emissiveFactor;
|
|
|
+ const originalPBRMetallicRoughness = originalMaterial.pbrMetallicRoughness;
|
|
|
+ if (originalPBRMetallicRoughness) {
|
|
|
+ newMaterial.pbrMetallicRoughness = {};
|
|
|
+ newMaterial.pbrMetallicRoughness.baseColorFactor = originalPBRMetallicRoughness.baseColorFactor;
|
|
|
+ newMaterial.pbrMetallicRoughness.metallicFactor = originalPBRMetallicRoughness.metallicFactor;
|
|
|
+ newMaterial.pbrMetallicRoughness.roughnessFactor = originalPBRMetallicRoughness.roughnessFactor;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return newMaterial;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Specifies if the material has any texture parameters present.
|
|
|
+ * @param material - glTF Material.
|
|
|
+ * @returns boolean specifying if texture parameters are present
|
|
|
+ */
|
|
|
+ public static HasTexturesPresent(material: IMaterial): boolean {
|
|
|
+ if (material.emissiveTexture || material.normalTexture || material.occlusionTexture) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ const pbrMat = material.pbrMetallicRoughness;
|
|
|
+ if (pbrMat) {
|
|
|
+ if (pbrMat.baseColorTexture || pbrMat.metallicRoughnessTexture) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -98,7 +149,6 @@ module BABYLON.GLTF2 {
|
|
|
return glTFPbrMetallicRoughness;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* Computes the metallic factor
|
|
|
* @param diffuse - diffused value
|
|
@@ -158,6 +208,28 @@ module BABYLON.GLTF2 {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ else if (babylonMaterial instanceof PBRMaterial) {
|
|
|
+ const babylonPBRMaterial = babylonMaterial as PBRMaterial;
|
|
|
+
|
|
|
+ switch (babylonPBRMaterial.transparencyMode) {
|
|
|
+ case PBRMaterial.PBRMATERIAL_OPAQUE: {
|
|
|
+ return MaterialAlphaMode.OPAQUE;
|
|
|
+ }
|
|
|
+ case PBRMaterial.PBRMATERIAL_ALPHABLEND: {
|
|
|
+ return MaterialAlphaMode.BLEND;
|
|
|
+ }
|
|
|
+ case PBRMaterial.PBRMATERIAL_ALPHATEST: {
|
|
|
+ return MaterialAlphaMode.MASK;
|
|
|
+ }
|
|
|
+ case PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
|
|
|
+ Tools.Warn(babylonMaterial.name + ": GLTF Exporter | Alpha test and blend mode not supported in glTF. Alpha blend used instead.");
|
|
|
+ return MaterialAlphaMode.BLEND;
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ throw new Error("Unsupported alpha mode " + babylonPBRMaterial.transparencyMode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
else {
|
|
|
throw new Error("Unsupported Babylon material type");
|
|
|
}
|
|
@@ -205,9 +277,13 @@ module BABYLON.GLTF2 {
|
|
|
glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
|
|
|
}
|
|
|
if (babylonStandardMaterial.ambientTexture) {
|
|
|
- const glTFOcclusionTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.ambientTexture, mimeType, images, textures, imageData)
|
|
|
- if (glTFOcclusionTexture) {
|
|
|
- glTFMaterial.occlusionTexture = glTFOcclusionTexture;
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.ambientTexture, mimeType, images, textures, imageData);
|
|
|
+ if (glTFTexture) {
|
|
|
+ const occlusionTexture: IMaterialOcclusionTextureInfo = {
|
|
|
+ index: glTFTexture.index
|
|
|
+ };
|
|
|
+ glTFMaterial.occlusionTexture = occlusionTexture;
|
|
|
+ occlusionTexture.strength = 1.0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -316,6 +392,158 @@ module BABYLON.GLTF2 {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
|
|
|
+ * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
|
|
|
+ * @param color - Color source to calculate brightness from.
|
|
|
+ * @returns number representing the perceived brightness, or zero if color is undefined.
|
|
|
+ */
|
|
|
+ public static GetPerceivedBrightness(color: Color3): number {
|
|
|
+ if (color) {
|
|
|
+ return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the maximum color component value.
|
|
|
+ * @param color
|
|
|
+ * @returns maximum color component value, or zero if color is null or undefined.
|
|
|
+ */
|
|
|
+ public static GetMaxComponent(color: Color3): number {
|
|
|
+ if (color) {
|
|
|
+ return Math.max(color.r, Math.max(color.g, color.b));
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
|
|
|
+ * @param babylonPBRMaterial - BJS PBR Metallic Roughness Material.
|
|
|
+ * @param mimeType - mime type to use for the textures.
|
|
|
+ * @param images - array of glTF image interfaces.
|
|
|
+ * @param textures - array of glTF texture interfaces.
|
|
|
+ * @param materials - array of glTF material interfaces.
|
|
|
+ * @param imageData - map of image file name to data.
|
|
|
+ * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
|
|
|
+ */
|
|
|
+ public static ConvertPBRMaterial(babylonPBRMaterial: PBRMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }, hasTextureCoords: boolean) {
|
|
|
+ const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {};
|
|
|
+ const glTFMaterial: IMaterial = {
|
|
|
+ name: babylonPBRMaterial.name
|
|
|
+ };
|
|
|
+ const useMetallicRoughness = babylonPBRMaterial.isMetallicWorkflow();
|
|
|
+
|
|
|
+ if (babylonPBRMaterial) {
|
|
|
+ if (useMetallicRoughness) {
|
|
|
+ glTFPbrMetallicRoughness.baseColorFactor = [
|
|
|
+ babylonPBRMaterial.albedoColor.r,
|
|
|
+ babylonPBRMaterial.albedoColor.g,
|
|
|
+ babylonPBRMaterial.albedoColor.b,
|
|
|
+ babylonPBRMaterial.alpha
|
|
|
+ ];
|
|
|
+ if (babylonPBRMaterial.metallic != null) {
|
|
|
+ if (babylonPBRMaterial.metallic !== 1) {
|
|
|
+ glTFPbrMetallicRoughness.metallicFactor = babylonPBRMaterial.metallic;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (babylonPBRMaterial.roughness != null) {
|
|
|
+ if (babylonPBRMaterial.roughness !== 1) {
|
|
|
+ glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMaterial.roughness;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ const diffuseColor = babylonPBRMaterial.albedoColor || Color3.Black();
|
|
|
+ const specularColor = babylonPBRMaterial.reflectionColor || Color3.Black();
|
|
|
+ const diffusePerceivedBrightness = _GLTFMaterial.GetPerceivedBrightness(diffuseColor);
|
|
|
+ const specularPerceivedBrightness = _GLTFMaterial.GetPerceivedBrightness(specularColor);
|
|
|
+ const oneMinusSpecularStrength = 1 - _GLTFMaterial.GetMaxComponent(babylonPBRMaterial.reflectionColor);
|
|
|
+ const metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
|
|
|
+ const glossiness = babylonPBRMaterial.microSurface || 0;
|
|
|
+ const baseColorFromDiffuse = diffuseColor.scale(oneMinusSpecularStrength / (1.0 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon));
|
|
|
+ const baseColorFromSpecular = specularColor.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1 / Math.max(metallic, this.epsilon));
|
|
|
+ let baseColor = Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
|
|
|
+ baseColor = baseColor.clampToRef(0, 1, baseColor);
|
|
|
+
|
|
|
+ glTFPbrMetallicRoughness.baseColorFactor = [
|
|
|
+ baseColor.r,
|
|
|
+ baseColor.g,
|
|
|
+ baseColor.b,
|
|
|
+ babylonPBRMaterial.alpha
|
|
|
+ ];
|
|
|
+ if (metallic !== 1) {
|
|
|
+ glTFPbrMetallicRoughness.metallicFactor = metallic;
|
|
|
+ }
|
|
|
+ if (glossiness) {
|
|
|
+ glTFPbrMetallicRoughness.roughnessFactor = 1 - glossiness;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (babylonPBRMaterial.backFaceCulling) {
|
|
|
+ if (!babylonPBRMaterial.twoSidedLighting) {
|
|
|
+ Tools.Warn(babylonPBRMaterial.name + ": Back-face culling enabled and two-sided lighting disabled is not supported in glTF.");
|
|
|
+ }
|
|
|
+ glTFMaterial.doubleSided = true;
|
|
|
+ }
|
|
|
+ if (hasTextureCoords) {
|
|
|
+ if (babylonPBRMaterial.albedoTexture) {
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.albedoTexture, mimeType, images, textures, imageData);
|
|
|
+ if (glTFTexture) {
|
|
|
+ glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (babylonPBRMaterial.bumpTexture) {
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.bumpTexture, mimeType, images, textures, imageData);
|
|
|
+ if (glTFTexture) {
|
|
|
+ glTFMaterial.normalTexture = glTFTexture;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (babylonPBRMaterial.ambientTexture) {
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.ambientTexture, mimeType, images, textures, imageData);
|
|
|
+ if (glTFTexture) {
|
|
|
+ let occlusionTexture: IMaterialOcclusionTextureInfo = {
|
|
|
+ index: glTFTexture.index
|
|
|
+ };
|
|
|
+
|
|
|
+ glTFMaterial.occlusionTexture = occlusionTexture;
|
|
|
+
|
|
|
+ if (babylonPBRMaterial.ambientTextureStrength) {
|
|
|
+ occlusionTexture.strength = babylonPBRMaterial.ambientTextureStrength;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (babylonPBRMaterial.emissiveTexture) {
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.emissiveTexture, mimeType, images, textures, imageData);
|
|
|
+ if (glTFTexture != null) {
|
|
|
+ glTFMaterial.emissiveTexture = glTFTexture;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (babylonPBRMaterial.metallicTexture) {
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.metallicTexture, mimeType, images, textures, imageData);
|
|
|
+ if (glTFTexture != null) {
|
|
|
+ glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFTexture;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!babylonPBRMaterial.emissiveColor.equalsFloats(0.0, 0.0, 0.0)) {
|
|
|
+ glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();
|
|
|
+ }
|
|
|
+ if (babylonPBRMaterial.transparencyMode != null) {
|
|
|
+ const alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
|
|
|
+
|
|
|
+ if (alphaMode !== MaterialAlphaMode.OPAQUE) { //glTF defaults to opaque
|
|
|
+ glTFMaterial.alphaMode = alphaMode;
|
|
|
+ if (alphaMode === MaterialAlphaMode.BLEND) {
|
|
|
+ glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
|
|
|
+ materials.push(glTFMaterial);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* Extracts a texture from a Babylon texture into file data and glTF data.
|
|
|
* @param babylonTexture - Babylon texture to extract.
|
|
|
* @param mimeType - Mime Type of the babylonTexture.
|