|
@@ -2,62 +2,40 @@
|
|
|
|
|
|
module BABYLON.GLTF2 {
|
|
module BABYLON.GLTF2 {
|
|
/**
|
|
/**
|
|
- * Represents the components used for representing a physically-based specular glossiness material
|
|
|
|
|
|
+ * Utility methods for working with glTF material conversion properties. This class should only be used internally.
|
|
*/
|
|
*/
|
|
- interface IBabylonPbrSpecularGlossiness {
|
|
|
|
- /**
|
|
|
|
- * The diffuse color of the model, whose color values should be
|
|
|
|
- * normalized from 0 to 1.
|
|
|
|
- */
|
|
|
|
- diffuse: Color3;
|
|
|
|
- /**
|
|
|
|
- * Represents the transparency of the material, from a range of 0 to 1.
|
|
|
|
- */
|
|
|
|
- opacity: number;
|
|
|
|
- /**
|
|
|
|
- * Represents how specular the material is, from a range of 0 to 1.
|
|
|
|
- */
|
|
|
|
- specular: Color3;
|
|
|
|
|
|
+ export class _GLTFMaterial {
|
|
/**
|
|
/**
|
|
- * Represents how glossy the material is, from a range of 0 to 1.
|
|
|
|
|
|
+ * Represents the dielectric specular values for R, G and B.
|
|
*/
|
|
*/
|
|
- glossiness: number;
|
|
|
|
- }
|
|
|
|
|
|
+ private static readonly dielectricSpecular: Color3 = new Color3(0.04, 0.04, 0.04);
|
|
|
|
|
|
- /**
|
|
|
|
- * Represents the components used for representing a physically-based metallic roughness material.
|
|
|
|
- */
|
|
|
|
- interface _IBabylonPbrMetallicRoughness {
|
|
|
|
- /**
|
|
|
|
- * The albedo color of the material, whose color components should be normalized from 0 to 1.
|
|
|
|
- */
|
|
|
|
- baseColor: Color3;
|
|
|
|
- /**
|
|
|
|
- * Represents the transparency of the material, from a range of 0 (transparent) to 1 (opaque).
|
|
|
|
- */
|
|
|
|
- opacity: number;
|
|
|
|
- /**
|
|
|
|
- * Represents the "metalness" of a material, from a range of 0 (dielectric) to 1 (metal).
|
|
|
|
- */
|
|
|
|
- metallic: number;
|
|
|
|
/**
|
|
/**
|
|
- * Represents the "roughness" of a material, from a range of 0 (completely smooth) to 1 (completely rough).
|
|
|
|
|
|
+ * Allows the maximum specular power to be defined for material calculations.
|
|
*/
|
|
*/
|
|
- roughness: number;
|
|
|
|
- }
|
|
|
|
|
|
+ private static maxSpecularPower = 1024;
|
|
|
|
|
|
- /**
|
|
|
|
- * Utility methods for working with glTF material conversion properties. This class should only be used internally.
|
|
|
|
- */
|
|
|
|
- export class _GLTFMaterial {
|
|
|
|
/**
|
|
/**
|
|
- * Represents the dielectric specular values for R, G and B.
|
|
|
|
- */
|
|
|
|
- private static readonly dielectricSpecular = new Color3(0.04, 0.04, 0.04);
|
|
|
|
- /**
|
|
|
|
- * Epsilon value, used as a small tolerance value for a numeric value.
|
|
|
|
|
|
+ * Gets the materials from a Babylon scene and converts them to glTF materials.
|
|
|
|
+ * @param scene
|
|
|
|
+ * @param mimeType
|
|
|
|
+ * @param images
|
|
|
|
+ * @param textures
|
|
|
|
+ * @param materials
|
|
|
|
+ * @param imageData
|
|
|
|
+ * @param hasTextureCoords
|
|
*/
|
|
*/
|
|
- private static readonly epsilon = 1e-6;
|
|
|
|
|
|
+ public static ConvertMaterialsToGLTF(babylonMaterials: Material[], mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }, hasTextureCoords: boolean) {
|
|
|
|
+ for (let i = 0; i < babylonMaterials.length; ++i) {
|
|
|
|
+ const babylonMaterial = babylonMaterials[i];
|
|
|
|
+ if (babylonMaterial instanceof StandardMaterial) {
|
|
|
|
+ _GLTFMaterial.ConvertStandardMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
|
|
|
|
+ }
|
|
|
|
+ else if (babylonMaterial instanceof PBRMetallicRoughnessMaterial) {
|
|
|
|
+ _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
/**
|
|
* Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
|
|
* Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
|
|
@@ -65,72 +43,61 @@ module BABYLON.GLTF2 {
|
|
* @returns - glTF Metallic Roughness Material representation
|
|
* @returns - glTF Metallic Roughness Material representation
|
|
*/
|
|
*/
|
|
public static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness {
|
|
public static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness {
|
|
- const babylonSpecularGlossiness: IBabylonPbrSpecularGlossiness = {
|
|
|
|
- diffuse: babylonStandardMaterial.diffuseColor,
|
|
|
|
- opacity: babylonStandardMaterial.alpha,
|
|
|
|
- specular: babylonStandardMaterial.specularColor || Color3.Black(),
|
|
|
|
- glossiness: babylonStandardMaterial.specularPower / 256
|
|
|
|
- };
|
|
|
|
- if (babylonStandardMaterial.specularTexture) {
|
|
|
|
|
|
+ const P0 = new BABYLON.Vector2(0, 1);
|
|
|
|
+ const P1 = new BABYLON.Vector2(0, 0.1);
|
|
|
|
+ const P2 = new BABYLON.Vector2(0, 0.1);
|
|
|
|
+ const P3 = new BABYLON.Vector2(1300, 0.1);
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Given the control points, solve for x based on a given t for a cubic bezier curve.
|
|
|
|
+ * @param t - a value between 0 and 1.
|
|
|
|
+ * @param p0 - first control point.
|
|
|
|
+ * @param p1 - second control point.
|
|
|
|
+ * @param p2 - third control point.
|
|
|
|
+ * @param p3 - fourth control point.
|
|
|
|
+ * @returns - number result of cubic bezier curve at the specified t.
|
|
|
|
+ */
|
|
|
|
+ function cubicBezierCurve(t: number, p0: number, p1: number, p2: number, p3: number): number {
|
|
|
|
+ return (
|
|
|
|
+ (1 - t) * (1 - t) * (1 - t) * p0 +
|
|
|
|
+ 3 * (1 - t) * (1 - t) * t * p1 +
|
|
|
|
+ 3 * (1 - t) * t * t * p2 +
|
|
|
|
+ t * t * t * p3
|
|
|
|
+ );
|
|
}
|
|
}
|
|
- const babylonMetallicRoughness = _GLTFMaterial._ConvertToMetallicRoughness(babylonSpecularGlossiness);
|
|
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Evaluates a specified specular power value to determine the appropriate roughness value,
|
|
|
|
+ * based on a pre-defined cubic bezier curve with specular on the abscissa axis (x-axis)
|
|
|
|
+ * and roughness on the ordinant axis (y-axis).
|
|
|
|
+ * @param specularPower - specular power of standard material.
|
|
|
|
+ * @returns - Number representing the roughness value.
|
|
|
|
+ */
|
|
|
|
+ function solveForRoughness(specularPower: number): number {
|
|
|
|
+ var t = Math.pow(specularPower / P3.x, 0.333333);
|
|
|
|
+ return cubicBezierCurve(t, P0.y, P1.y, P2.y, P3.y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let diffuse = babylonStandardMaterial.diffuseColor.toLinearSpace().scale(0.5);
|
|
|
|
+ let opacity = babylonStandardMaterial.alpha;
|
|
|
|
+ let specularPower = Scalar.Clamp(babylonStandardMaterial.specularPower, 0, this.maxSpecularPower);
|
|
|
|
+
|
|
|
|
+ const roughness = solveForRoughness(specularPower);
|
|
|
|
|
|
const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {
|
|
const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {
|
|
baseColorFactor: [
|
|
baseColorFactor: [
|
|
- babylonMetallicRoughness.baseColor.r,
|
|
|
|
- babylonMetallicRoughness.baseColor.g,
|
|
|
|
- babylonMetallicRoughness.baseColor.b,
|
|
|
|
- babylonMetallicRoughness.opacity
|
|
|
|
|
|
+ diffuse.r,
|
|
|
|
+ diffuse.g,
|
|
|
|
+ diffuse.b,
|
|
|
|
+ opacity
|
|
],
|
|
],
|
|
- metallicFactor: babylonMetallicRoughness.metallic,
|
|
|
|
- roughnessFactor: babylonMetallicRoughness.roughness
|
|
|
|
|
|
+ metallicFactor: 0,
|
|
|
|
+ roughnessFactor: roughness,
|
|
};
|
|
};
|
|
|
|
|
|
return glTFPbrMetallicRoughness;
|
|
return glTFPbrMetallicRoughness;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * Converts Specular Glossiness to Metallic Roughness. This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
|
|
|
|
- * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
|
|
|
|
- * @param babylonSpecularGlossiness - Babylon specular glossiness parameters
|
|
|
|
- * @returns - Babylon metallic roughness values
|
|
|
|
- */
|
|
|
|
- private static _ConvertToMetallicRoughness(babylonSpecularGlossiness: IBabylonPbrSpecularGlossiness): _IBabylonPbrMetallicRoughness {
|
|
|
|
- const diffuse = babylonSpecularGlossiness.diffuse;
|
|
|
|
- const opacity = babylonSpecularGlossiness.opacity;
|
|
|
|
- const specular = babylonSpecularGlossiness.specular;
|
|
|
|
- const glossiness = BABYLON.Scalar.Clamp(babylonSpecularGlossiness.glossiness);
|
|
|
|
-
|
|
|
|
- const oneMinusSpecularStrength = 1 - Math.max(specular.r, Math.max(specular.g, specular.b));
|
|
|
|
- const diffusePerceivedBrightness = _GLTFMaterial.PerceivedBrightness(diffuse);
|
|
|
|
- const specularPerceivedBrightness = _GLTFMaterial.PerceivedBrightness(specular);
|
|
|
|
- const metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
|
|
|
|
- const diffuseScaleFactor = oneMinusSpecularStrength/(1 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon);
|
|
|
|
- const baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
|
|
|
|
- const baseColorFromSpecular = specular.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1/ Math.max(metallic, this.epsilon));
|
|
|
|
- const lerpColor = Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
|
|
|
|
- let baseColor = new Color3();
|
|
|
|
- lerpColor.clampToRef(0, 1, baseColor);
|
|
|
|
-
|
|
|
|
- const babylonMetallicRoughness: _IBabylonPbrMetallicRoughness = {
|
|
|
|
- baseColor: baseColor,
|
|
|
|
- opacity: opacity,
|
|
|
|
- metallic: metallic,
|
|
|
|
- roughness: 1.0 - glossiness
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- return babylonMetallicRoughness;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Returns the perceived brightness value based on the provided color
|
|
|
|
- * @param color - color used in calculating the perceived brightness
|
|
|
|
- * @returns - perceived brightness value
|
|
|
|
- */
|
|
|
|
- private static PerceivedBrightness(color: Color3): number {
|
|
|
|
- return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
|
|
|
|
- }
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* Computes the metallic factor
|
|
* Computes the metallic factor
|
|
@@ -140,17 +107,18 @@ module BABYLON.GLTF2 {
|
|
* @returns - metallic value
|
|
* @returns - metallic value
|
|
*/
|
|
*/
|
|
public static SolveMetallic(diffuse: number, specular: number, oneMinusSpecularStrength: number): number {
|
|
public static SolveMetallic(diffuse: number, specular: number, oneMinusSpecularStrength: number): number {
|
|
- if (specular < this.dielectricSpecular.r) {
|
|
|
|
|
|
+ if (specular < _GLTFMaterial.dielectricSpecular.r) {
|
|
|
|
+ _GLTFMaterial.dielectricSpecular
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- const a = this.dielectricSpecular.r;
|
|
|
|
- const b = diffuse * oneMinusSpecularStrength /(1.0 - this.dielectricSpecular.r) + specular - 2.0 * this.dielectricSpecular.r;
|
|
|
|
- const c = this.dielectricSpecular.r - specular;
|
|
|
|
|
|
+ const a = _GLTFMaterial.dielectricSpecular.r;
|
|
|
|
+ const b = diffuse * oneMinusSpecularStrength / (1.0 - _GLTFMaterial.dielectricSpecular.r) + specular - 2.0 * _GLTFMaterial.dielectricSpecular.r;
|
|
|
|
+ const c = _GLTFMaterial.dielectricSpecular.r - specular;
|
|
const D = b * b - 4.0 * a * c;
|
|
const D = b * b - 4.0 * a * c;
|
|
- return BABYLON.Scalar.Clamp((-b + Math.sqrt(D))/(2.0 * a));
|
|
|
|
|
|
+ return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a), 0, 1);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Gets the glTF alpha mode from the Babylon Material
|
|
* Gets the glTF alpha mode from the Babylon Material
|
|
* @param babylonMaterial - Babylon Material
|
|
* @param babylonMaterial - Babylon Material
|
|
@@ -159,10 +127,10 @@ module BABYLON.GLTF2 {
|
|
public static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode {
|
|
public static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode {
|
|
if (babylonMaterial instanceof StandardMaterial) {
|
|
if (babylonMaterial instanceof StandardMaterial) {
|
|
const babylonStandardMaterial = babylonMaterial as StandardMaterial;
|
|
const babylonStandardMaterial = babylonMaterial as StandardMaterial;
|
|
- if ((babylonStandardMaterial.alpha != 1.0) ||
|
|
|
|
|
|
+ if ((babylonStandardMaterial.alpha != 1.0) ||
|
|
(babylonStandardMaterial.diffuseTexture != null && babylonStandardMaterial.diffuseTexture.hasAlpha) ||
|
|
(babylonStandardMaterial.diffuseTexture != null && babylonStandardMaterial.diffuseTexture.hasAlpha) ||
|
|
(babylonStandardMaterial.opacityTexture != null)) {
|
|
(babylonStandardMaterial.opacityTexture != null)) {
|
|
- return MaterialAlphaMode.BLEND;
|
|
|
|
|
|
+ return MaterialAlphaMode.BLEND;
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
return MaterialAlphaMode.OPAQUE;
|
|
return MaterialAlphaMode.OPAQUE;
|
|
@@ -171,7 +139,7 @@ module BABYLON.GLTF2 {
|
|
else if (babylonMaterial instanceof PBRMetallicRoughnessMaterial) {
|
|
else if (babylonMaterial instanceof PBRMetallicRoughnessMaterial) {
|
|
const babylonPBRMetallicRoughness = babylonMaterial as PBRMetallicRoughnessMaterial;
|
|
const babylonPBRMetallicRoughness = babylonMaterial as PBRMetallicRoughnessMaterial;
|
|
|
|
|
|
- switch(babylonPBRMetallicRoughness.transparencyMode) {
|
|
|
|
|
|
+ switch (babylonPBRMetallicRoughness.transparencyMode) {
|
|
case PBRMaterial.PBRMATERIAL_OPAQUE: {
|
|
case PBRMaterial.PBRMATERIAL_OPAQUE: {
|
|
return MaterialAlphaMode.OPAQUE;
|
|
return MaterialAlphaMode.OPAQUE;
|
|
}
|
|
}
|
|
@@ -182,7 +150,7 @@ module BABYLON.GLTF2 {
|
|
return MaterialAlphaMode.MASK;
|
|
return MaterialAlphaMode.MASK;
|
|
}
|
|
}
|
|
case PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
|
|
case PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
|
|
- console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF. Alpha blend used instead.");
|
|
|
|
|
|
+ Tools.Warn(babylonMaterial.name + ": GLTF Exporter | Alpha test and blend mode not supported in glTF. Alpha blend used instead.");
|
|
return MaterialAlphaMode.BLEND;
|
|
return MaterialAlphaMode.BLEND;
|
|
}
|
|
}
|
|
default: {
|
|
default: {
|
|
@@ -192,7 +160,254 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
throw new Error("Unsupported Babylon material type");
|
|
throw new Error("Unsupported Babylon material type");
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Converts a Babylon Standard Material to a glTF Material.
|
|
|
|
+ * @param babylonStandardMaterial - BJS Standard 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 ConvertStandardMaterial(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }, hasTextureCoords: boolean) {
|
|
|
|
+ Tools.Warn(babylonStandardMaterial.name + ": Standard Material is currently not fully supported/implemented in glTF serializer");
|
|
|
|
+ const glTFPbrMetallicRoughness = _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
|
|
|
|
+
|
|
|
|
+ const glTFMaterial: IMaterial = { name: babylonStandardMaterial.name };
|
|
|
|
+ if (babylonStandardMaterial.backFaceCulling) {
|
|
|
|
+ if (!babylonStandardMaterial.twoSidedLighting) {
|
|
|
|
+ Tools.Warn(babylonStandardMaterial.name + ": Back-face culling enabled and two-sided lighting disabled is not supported in glTF.");
|
|
|
|
+ }
|
|
|
|
+ glTFMaterial.doubleSided = true;
|
|
|
|
+ }
|
|
|
|
+ if (hasTextureCoords) {
|
|
|
|
+ if (babylonStandardMaterial.diffuseTexture) {
|
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.diffuseTexture, mimeType, images, textures, imageData);
|
|
|
|
+ if (glTFTexture != null) {
|
|
|
|
+ glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (babylonStandardMaterial.bumpTexture) {
|
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.bumpTexture, mimeType, images, textures, imageData)
|
|
|
|
+ if (glTFTexture) {
|
|
|
|
+ glTFMaterial.normalTexture = glTFTexture;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (babylonStandardMaterial.emissiveTexture) {
|
|
|
|
+ const glTFEmissiveTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.emissiveTexture, mimeType, images, textures, imageData)
|
|
|
|
+ if (glTFEmissiveTexture) {
|
|
|
|
+ glTFMaterial.emissiveTexture = glTFEmissiveTexture;
|
|
|
|
+ }
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
|
|
|
|
+
|
|
|
|
+ if (babylonStandardMaterial.alphaMode === Engine.ALPHA_COMBINE) {
|
|
|
|
+ glTFMaterial.alphaMode = GLTF2.MaterialAlphaMode.BLEND;
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
|
|
|
|
+
|
|
|
|
+ materials.push(glTFMaterial);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
|
|
|
|
+ * @param babylonPBRMetalRoughMaterial - 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 ConvertPBRMetallicRoughnessMaterial(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }, hasTextureCoords: boolean) {
|
|
|
|
+ const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {};
|
|
|
|
+
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.baseColor) {
|
|
|
|
+ glTFPbrMetallicRoughness.baseColorFactor = [
|
|
|
|
+ babylonPBRMetalRoughMaterial.baseColor.r,
|
|
|
|
+ babylonPBRMetalRoughMaterial.baseColor.g,
|
|
|
|
+ babylonPBRMetalRoughMaterial.baseColor.b,
|
|
|
|
+ babylonPBRMetalRoughMaterial.alpha
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.metallic != null) {
|
|
|
|
+ glTFPbrMetallicRoughness.metallicFactor = babylonPBRMetalRoughMaterial.metallic;
|
|
|
|
+ }
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.roughness != null) {
|
|
|
|
+ glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMetalRoughMaterial.roughness;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const glTFMaterial: IMaterial = {
|
|
|
|
+ name: babylonPBRMetalRoughMaterial.name
|
|
|
|
+ };
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.doubleSided) {
|
|
|
|
+ glTFMaterial.doubleSided = babylonPBRMetalRoughMaterial.doubleSided;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (hasTextureCoords) {
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.baseTexture != null) {
|
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.baseTexture, mimeType, images, textures, imageData);
|
|
|
|
+ if (glTFTexture != null) {
|
|
|
|
+ glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.normalTexture) {
|
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.normalTexture, mimeType, images, textures, imageData);
|
|
|
|
+ if (glTFTexture) {
|
|
|
|
+ glTFMaterial.normalTexture = glTFTexture;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.occlusionTexture) {
|
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.occlusionTexture, mimeType, images, textures, imageData);
|
|
|
|
+ if (glTFTexture) {
|
|
|
|
+ glTFMaterial.occlusionTexture = glTFTexture;
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.occlusionStrength != null) {
|
|
|
|
+ glTFMaterial.occlusionTexture.strength = babylonPBRMetalRoughMaterial.occlusionStrength;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.emissiveTexture) {
|
|
|
|
+ const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.emissiveTexture, mimeType, images, textures, imageData);
|
|
|
|
+ if (glTFTexture != null) {
|
|
|
|
+ glTFMaterial.emissiveTexture = glTFTexture;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.emissiveColor.equalsFloats(0.0, 0.0, 0.0)) {
|
|
|
|
+ glTFMaterial.emissiveFactor = babylonPBRMetalRoughMaterial.emissiveColor.asArray();
|
|
|
|
+ }
|
|
|
|
+ if (babylonPBRMetalRoughMaterial.transparencyMode != null) {
|
|
|
|
+ const alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMetalRoughMaterial);
|
|
|
|
+
|
|
|
|
+ if (alphaMode !== MaterialAlphaMode.OPAQUE) { //glTF defaults to opaque
|
|
|
|
+ glTFMaterial.alphaMode = alphaMode;
|
|
|
|
+ if (alphaMode === MaterialAlphaMode.BLEND) {
|
|
|
|
+ glTFMaterial.alphaCutoff = babylonPBRMetalRoughMaterial.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.
|
|
|
|
+ * @param images - Array of glTF images.
|
|
|
|
+ * @param textures - Array of glTF textures.
|
|
|
|
+ * @param imageData - map of image file name and data.
|
|
|
|
+ * @return - glTF texture, or null if the texture format is not supported.
|
|
|
|
+ */
|
|
|
|
+ public static ExportTexture(babylonTexture: BaseTexture, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }): Nullable<ITextureInfo> {
|
|
|
|
+ let textureInfo: Nullable<ITextureInfo> = null;
|
|
|
|
+
|
|
|
|
+ let glTFTexture = {
|
|
|
|
+ source: images.length
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ let textureName = "texture_" + (textures.length - 1).toString();
|
|
|
|
+ let textureData = babylonTexture.getInternalTexture();
|
|
|
|
+
|
|
|
|
+ if (textureData != null) {
|
|
|
|
+ textureName = textureData.url;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ textureName = Tools.GetFilename(textureName);
|
|
|
|
+ const baseFile = textureName.split('.')[0];
|
|
|
|
+ let extension = "";
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (mimeType === ImageMimeType.JPEG) {
|
|
|
|
+ extension = ".jpg";
|
|
|
|
+ }
|
|
|
|
+ else if (mimeType === ImageMimeType.PNG) {
|
|
|
|
+ extension = ".png";
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ Tools.Error("Unsupported mime type " + mimeType);
|
|
|
|
+ }
|
|
|
|
+ textureName = baseFile + extension;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ const pixels = babylonTexture.readPixels() as Uint8Array;
|
|
|
|
+
|
|
|
|
+ const imageCanvas = document.createElement('canvas');
|
|
|
|
+ imageCanvas.id = "ImageCanvas";
|
|
|
|
+
|
|
|
|
+ const ctx = <CanvasRenderingContext2D>imageCanvas.getContext('2d');
|
|
|
|
+ const size = babylonTexture.getSize();
|
|
|
|
+ imageCanvas.width = size.width;
|
|
|
|
+ imageCanvas.height = size.height;
|
|
|
|
+
|
|
|
|
+ const imgData = ctx.createImageData(size.width, size.height);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ imgData.data.set(pixels);
|
|
|
|
+ ctx.putImageData(imgData, 0, 0);
|
|
|
|
+ const base64Data = imageCanvas.toDataURL(mimeType);
|
|
|
|
+ const binStr = atob(base64Data.split(',')[1]);
|
|
|
|
+ const arr = new Uint8Array(binStr.length);
|
|
|
|
+ for (let i = 0; i < binStr.length; ++i) {
|
|
|
|
+ arr[i] = binStr.charCodeAt(i);
|
|
|
|
+ }
|
|
|
|
+ const imageValues = { data: arr, mimeType: mimeType };
|
|
|
|
+
|
|
|
|
+ imageData[textureName] = imageValues;
|
|
|
|
+ if (mimeType === ImageMimeType.JPEG) {
|
|
|
|
+ const glTFImage: IImage = {
|
|
|
|
+ uri: textureName
|
|
|
|
+ }
|
|
|
|
+ let foundIndex = -1;
|
|
|
|
+ for (let i = 0; i < images.length; ++i) {
|
|
|
|
+ if (images[i].uri === textureName) {
|
|
|
|
+ foundIndex = i;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (foundIndex === -1) {
|
|
|
|
+ images.push(glTFImage);
|
|
|
|
+ glTFTexture.source = images.length - 1;
|
|
|
|
+ textures.push({
|
|
|
|
+ source: images.length - 1
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ textureInfo = {
|
|
|
|
+ index: images.length - 1
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ glTFTexture.source = foundIndex;
|
|
|
|
+
|
|
|
|
+ textureInfo = {
|
|
|
|
+ index: foundIndex
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return textureInfo;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|