123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- using BabylonExport.Entities;
- using GLTFExport.Entities;
- using System;
- using System.Drawing;
- using System.IO;
- namespace Max2Babylon
- {
- partial class BabylonExporter
- {
- private void ExportMaterial(BabylonMaterial babylonMaterial, GLTF gltf)
- {
- var name = babylonMaterial.name;
- var id = babylonMaterial.id;
- RaiseMessage("GLTFExporter.Material | Export material named: " + name, 1);
- if (babylonMaterial.GetType() == typeof(BabylonStandardMaterial))
- {
- var babylonStandardMaterial = babylonMaterial as BabylonStandardMaterial;
- // --- prints ---
- RaiseMessage("GLTFExporter.Material | babylonMaterial data", 2);
- RaiseMessage("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
- RaiseMessage("GLTFExporter.Material | babylonMaterial.alphaMode=" + babylonMaterial.alphaMode, 3);
- RaiseMessage("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
- RaiseMessage("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);
- // Ambient
- for (int i = 0; i < babylonStandardMaterial.ambient.Length; i++)
- {
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambient[" + i + "]=" + babylonStandardMaterial.ambient[i], 3);
- }
- // Diffuse
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuse.Length=" + babylonStandardMaterial.diffuse.Length, 3);
- for (int i = 0; i < babylonStandardMaterial.diffuse.Length; i++)
- {
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuse[" + i + "]=" + babylonStandardMaterial.diffuse[i], 3);
- }
- if (babylonStandardMaterial.diffuseTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuseTexture=null", 3);
- }
- // Normal / bump
- if (babylonStandardMaterial.bumpTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.bumpTexture=null", 3);
- }
- // Specular
- for (int i = 0; i < babylonStandardMaterial.specular.Length; i++)
- {
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specular[" + i + "]=" + babylonStandardMaterial.specular[i], 3);
- }
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specularPower=" + babylonStandardMaterial.specularPower, 3);
- // Occlusion
- if (babylonStandardMaterial.ambientTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambientTexture=null", 3);
- }
- // Emissive
- for (int i = 0; i < babylonStandardMaterial.emissive.Length; i++)
- {
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissive[" + i + "]=" + babylonStandardMaterial.emissive[i], 3);
- }
- if (babylonStandardMaterial.emissiveTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissiveTexture=null", 3);
- }
- // --------------------------------
- // --------- gltfMaterial ---------
- // --------------------------------
- RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
- var gltfMaterial = new GLTFMaterial
- {
- name = name
- };
- gltfMaterial.id = babylonMaterial.id;
- gltfMaterial.index = gltf.MaterialsList.Count;
- gltf.MaterialsList.Add(gltfMaterial);
- // Alpha
- string alphaMode;
- float? alphaCutoff;
- getAlphaMode(babylonStandardMaterial, out alphaMode, out alphaCutoff);
- gltfMaterial.alphaMode = alphaMode;
- gltfMaterial.alphaCutoff = alphaCutoff;
- // DoubleSided
- gltfMaterial.doubleSided = !babylonMaterial.backFaceCulling;
- // Normal
- gltfMaterial.normalTexture = ExportTexture(babylonStandardMaterial.bumpTexture, gltf);
- // Occulison
- gltfMaterial.occlusionTexture = ExportTexture(babylonStandardMaterial.ambientTexture, gltf);
- // Emissive
- gltfMaterial.emissiveFactor = babylonStandardMaterial.emissive;
- gltfMaterial.emissiveTexture = ExportTexture(babylonStandardMaterial.emissiveTexture, gltf);
- // --------------------------------
- // --- gltfPbrMetallicRoughness ---
- // --------------------------------
- RaiseMessage("GLTFExporter.Material | create gltfPbrMetallicRoughness", 2);
- var gltfPbrMetallicRoughness = new GLTFPBRMetallicRoughness();
- gltfMaterial.pbrMetallicRoughness = gltfPbrMetallicRoughness;
- // --- Global ---
- SpecularGlossiness _specularGlossiness = new SpecularGlossiness
- {
- diffuse = new BabylonColor3(babylonStandardMaterial.diffuse),
- opacity = babylonMaterial.alpha,
- specular = new BabylonColor3(babylonStandardMaterial.specular),
- glossiness = babylonStandardMaterial.specularPower / 256
- };
- MetallicRoughness _metallicRoughness = ConvertToMetallicRoughness(_specularGlossiness, true);
-
- // Base color
- gltfPbrMetallicRoughness.baseColorFactor = new float[4]
- {
- _metallicRoughness.baseColor.r,
- _metallicRoughness.baseColor.g,
- _metallicRoughness.baseColor.b,
- _metallicRoughness.opacity
- };
- // Metallic roughness
- gltfPbrMetallicRoughness.metallicFactor = _metallicRoughness.metallic;
- gltfPbrMetallicRoughness.roughnessFactor = _metallicRoughness.roughness;
- // --- Textures ---
- if (babylonStandardMaterial.diffuseTexture != null)
- {
- Func<string, Bitmap> loadTextureFromOutput = delegate (string textureName)
- {
- return LoadTexture(Path.Combine(gltf.OutputFolder, textureName));
- };
- Bitmap diffuseBitmap = loadTextureFromOutput(babylonStandardMaterial.diffuseTexture.name);
- if (diffuseBitmap != null)
- {
- Bitmap specularBitmap = null;
- if (babylonStandardMaterial.specularTexture != null)
- {
- specularBitmap = loadTextureFromOutput(babylonStandardMaterial.specularTexture.name);
- }
- Bitmap opacityBitmap = null;
- if (babylonStandardMaterial.diffuseTexture.hasAlpha == false && babylonStandardMaterial.opacityTexture != null)
- {
- opacityBitmap = loadTextureFromOutput(babylonStandardMaterial.opacityTexture.name);
- }
- // Retreive dimensions
- int width = 0;
- int height = 0;
- var haveSameDimensions = _getMinimalBitmapDimensions(out width, out height, diffuseBitmap, specularBitmap, opacityBitmap);
- if (!haveSameDimensions)
- {
- RaiseWarning("Diffuse, specular and opacity maps should have same dimensions", 2);
- }
- // Create base color and metallic+roughness maps
- Bitmap baseColorBitmap = new Bitmap(width, height);
- Bitmap metallicRoughnessBitmap = new Bitmap(width, height);
- var hasAlpha = false;
- for (int x = 0; x < width; x++)
- {
- for (int y = 0; y < height; y++)
- {
- var diffuse = diffuseBitmap.GetPixel(x, y);
- SpecularGlossiness specularGlossinessTexture = new SpecularGlossiness
- {
- diffuse = new BabylonColor3(diffuse),
- opacity = babylonStandardMaterial.diffuseTexture.hasAlpha? diffuse.A / 255.0f :
- opacityBitmap != null && babylonStandardMaterial.opacityTexture.getAlphaFromRGB ? opacityBitmap.GetPixel(x, y).R / 255.0f :
- opacityBitmap != null && babylonStandardMaterial.opacityTexture.getAlphaFromRGB == false ? opacityBitmap.GetPixel(x, y).A / 255.0f :
- 1,
- specular = specularBitmap != null ? new BabylonColor3(specularBitmap.GetPixel(x, y)) :
- new BabylonColor3(),
- glossiness = babylonStandardMaterial.useGlossinessFromSpecularMapAlpha && specularBitmap != null ? specularBitmap.GetPixel(x, y).A / 255.0f :
- 0
- };
- var displayPrints = x == width / 2 && y == height / 2;
- MetallicRoughness metallicRoughnessTexture = ConvertToMetallicRoughness(specularGlossinessTexture, displayPrints);
-
- Color colorBase = Color.FromArgb(
- (int)(metallicRoughnessTexture.opacity * 255),
- (int)(metallicRoughnessTexture.baseColor.r * 255),
- (int)(metallicRoughnessTexture.baseColor.g * 255),
- (int)(metallicRoughnessTexture.baseColor.b * 255)
- );
- baseColorBitmap.SetPixel(x, y, colorBase);
- if (metallicRoughnessTexture.opacity != 1)
- {
- hasAlpha = true;
- }
- // The metalness values are sampled from the B channel.
- // The roughness values are sampled from the G channel.
- // These values are linear. If other channels are present (R or A), they are ignored for metallic-roughness calculations.
- Color colorMetallicRoughness = Color.FromArgb(
- 0,
- (int)(metallicRoughnessTexture.roughness * 255),
- (int)(metallicRoughnessTexture.metallic * 255)
- );
- metallicRoughnessBitmap.SetPixel(x, y, colorMetallicRoughness);
- }
- }
- // Export maps and textures
- var baseColorFileName = babylonMaterial.name + "_baseColor" + (hasAlpha ? ".png" : ".jpg");
- gltfPbrMetallicRoughness.baseColorTexture = ExportBitmapTexture(babylonStandardMaterial.diffuseTexture, baseColorBitmap, baseColorFileName, gltf);
- if (specularBitmap != null)
- {
- gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportBitmapTexture(babylonStandardMaterial.diffuseTexture, metallicRoughnessBitmap, babylonMaterial.name + "_metallicRoughness" + ".jpg", gltf);
- }
- }
- }
- }
- else if (babylonMaterial.GetType() == typeof(BabylonPBRMetallicRoughnessMaterial))
- {
- var babylonPBRMetallicRoughnessMaterial = babylonMaterial as BabylonPBRMetallicRoughnessMaterial;
- // --- prints ---
- RaiseMessage("GLTFExporter.Material | babylonMaterial data", 2);
- RaiseMessage("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
- RaiseMessage("GLTFExporter.Material | babylonMaterial.alphaMode=" + babylonMaterial.alphaMode, 3);
- RaiseMessage("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
- RaiseMessage("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);
- // Global
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.maxSimultaneousLights=" + babylonPBRMetallicRoughnessMaterial.maxSimultaneousLights, 3);
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.disableLighting=" + babylonPBRMetallicRoughnessMaterial.disableLighting, 3);
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.alphaCutOff=" + babylonPBRMetallicRoughnessMaterial.alphaCutOff, 3);
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.transparencyMode=" + babylonPBRMetallicRoughnessMaterial.transparencyMode, 3);
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.doubleSided=" + babylonPBRMetallicRoughnessMaterial.doubleSided, 3);
- // Base color
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseColor.Length=" + babylonPBRMetallicRoughnessMaterial.baseColor.Length, 3);
- for (int i = 0; i < babylonPBRMetallicRoughnessMaterial.baseColor.Length; i++)
- {
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseColor[" + i + "]=" + babylonPBRMetallicRoughnessMaterial.baseColor[i], 3);
- }
- if (babylonPBRMetallicRoughnessMaterial.baseTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseTexture=null", 3);
- }
- // Metallic+roughness
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallic=" + babylonPBRMetallicRoughnessMaterial.metallic, 3);
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.roughness=" + babylonPBRMetallicRoughnessMaterial.roughness, 3);
- if (babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture=null", 3);
- }
- // Environment
- if (babylonPBRMetallicRoughnessMaterial.environmentTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.environmentTexture=null", 3);
- }
- // Normal / bump
- if (babylonPBRMetallicRoughnessMaterial.normalTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.normalTexture=null", 3);
- }
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.invertNormalMapX=" + babylonPBRMetallicRoughnessMaterial.invertNormalMapX, 3);
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.invertNormalMapY=" + babylonPBRMetallicRoughnessMaterial.invertNormalMapY, 3);
- // Emissive
- for (int i = 0; i < babylonPBRMetallicRoughnessMaterial.emissiveColor.Length; i++)
- {
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.emissiveColor[" + i + "]=" + babylonPBRMetallicRoughnessMaterial.emissiveColor[i], 3);
- }
- if (babylonPBRMetallicRoughnessMaterial.emissiveTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.emissiveTexture=null", 3);
- }
- // Ambient occlusion
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.occlusionStrength=" + babylonPBRMetallicRoughnessMaterial.occlusionStrength, 3);
- if (babylonPBRMetallicRoughnessMaterial.occlusionTexture == null)
- {
- RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.occlusionTexture=null", 3);
- }
- // --------------------------------
- // --------- gltfMaterial ---------
- // --------------------------------
- RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
- var gltfMaterial = new GLTFMaterial
- {
- name = name
- };
- gltfMaterial.id = babylonMaterial.id;
- gltfMaterial.index = gltf.MaterialsList.Count;
- gltf.MaterialsList.Add(gltfMaterial);
- // Alpha
- string alphaMode;
- float? alphaCutoff;
- getAlphaMode(babylonPBRMetallicRoughnessMaterial, out alphaMode, out alphaCutoff);
- gltfMaterial.alphaMode = alphaMode;
- gltfMaterial.alphaCutoff = alphaCutoff;
- // DoubleSided
- gltfMaterial.doubleSided = babylonPBRMetallicRoughnessMaterial.doubleSided;
- // Normal
- gltfMaterial.normalTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.normalTexture, gltf);
- // Occulison
- gltfMaterial.occlusionTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.occlusionTexture, gltf);
- // Emissive
- gltfMaterial.emissiveFactor = babylonPBRMetallicRoughnessMaterial.emissiveColor;
- gltfMaterial.emissiveTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.emissiveTexture, gltf);
- // --------------------------------
- // --- gltfPbrMetallicRoughness ---
- // --------------------------------
- RaiseMessage("GLTFExporter.Material | create gltfPbrMetallicRoughness", 2);
- var gltfPbrMetallicRoughness = new GLTFPBRMetallicRoughness();
- gltfMaterial.pbrMetallicRoughness = gltfPbrMetallicRoughness;
- // --- Global ---
- // Base color
- gltfPbrMetallicRoughness.baseColorFactor = new float[4]
- {
- babylonPBRMetallicRoughnessMaterial.baseColor[0],
- babylonPBRMetallicRoughnessMaterial.baseColor[1],
- babylonPBRMetallicRoughnessMaterial.baseColor[2],
- 1.0f // TODO - alpha
- };
- gltfPbrMetallicRoughness.baseColorTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.baseTexture, gltf);
- // Metallic roughness
- gltfPbrMetallicRoughness.metallicFactor = babylonPBRMetallicRoughnessMaterial.metallic;
- gltfPbrMetallicRoughness.roughnessFactor = babylonPBRMetallicRoughnessMaterial.roughness;
- gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture, gltf);
- }
- else
- {
- RaiseWarning("GLTFExporter.Material | Unsupported material type: " + babylonMaterial.GetType(), 2);
- }
- }
- private void getAlphaMode(BabylonStandardMaterial babylonMaterial, out string alphaMode, out float? alphaCutoff)
- {
- if ((babylonMaterial.diffuseTexture != null && babylonMaterial.diffuseTexture.hasAlpha) ||
- babylonMaterial.opacityTexture != null)
- {
- // TODO - Babylon standard material is assumed to useAlphaFromDiffuseTexture. If not, the alpha mode is a mask.
- alphaMode = GLTFMaterial.AlphaMode.BLEND.ToString();
- }
- else
- {
- // glTF alpha mode default value is "OPAQUE"
- alphaMode = null; // GLTFMaterial.AlphaMode.OPAQUE.ToString();
- }
- alphaCutoff = null;
- }
- private void getAlphaMode(BabylonPBRMetallicRoughnessMaterial babylonMaterial, out string alphaMode, out float? alphaCutoff)
- {
- if (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha)
- {
- // TODO - Babylon standard material is assumed to useAlphaFromDiffuseTexture. If not, the alpha mode is a mask.
- alphaMode = GLTFMaterial.AlphaMode.BLEND.ToString();
- }
- else
- {
- // glTF alpha mode default value is "OPAQUE"
- alphaMode = null; // GLTFMaterial.AlphaMode.OPAQUE.ToString();
- }
- alphaCutoff = null;
- }
- BabylonColor3 dielectricSpecular = new BabylonColor3(0.04f, 0.04f, 0.04f);
- const float epsilon = 1e-6f;
- private MetallicRoughness ConvertToMetallicRoughness(SpecularGlossiness specularGlossiness, bool displayPrints = false)
- {
- var diffuse = specularGlossiness.diffuse;
- var opacity = specularGlossiness.opacity;
- var specular = specularGlossiness.specular;
- var glossiness = specularGlossiness.glossiness;
- var oneMinusSpecularStrength = 1 - specular.getMaxComponent();
- var metallic = solveMetallic(diffuse.getPerceivedBrightness(), specular.getPerceivedBrightness(), oneMinusSpecularStrength);
- var diffuseScaleFactor = oneMinusSpecularStrength / (1 - dielectricSpecular.r) / Math.Max(1 - metallic, epsilon);
- var baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
- var baseColorFromSpecular = specular.subtract(dielectricSpecular.scale(1 - metallic)).scale(1 / Math.Max(metallic, epsilon));
- var baseColor = BabylonColor3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic).clamp();
- //var baseColor = baseColorFromDiffuse.clamp();
- if (displayPrints)
- {
- RaiseMessage("-----------------------", 3);
- RaiseMessage("diffuse=" + diffuse, 3);
- RaiseMessage("opacity=" + opacity, 3);
- RaiseMessage("specular=" + specular, 3);
- RaiseMessage("glossiness=" + glossiness, 3);
- RaiseMessage("oneMinusSpecularStrength=" + oneMinusSpecularStrength, 3);
- RaiseMessage("metallic=" + metallic, 3);
- RaiseMessage("diffuseScaleFactor=" + diffuseScaleFactor, 3);
- RaiseMessage("baseColorFromDiffuse=" + baseColorFromDiffuse, 3);
- RaiseMessage("baseColorFromSpecular=" + baseColorFromSpecular, 3);
- RaiseMessage("metallic * metallic=" + metallic * metallic, 3);
- RaiseMessage("baseColor=" + baseColor, 3);
- RaiseMessage("-----------------------", 3);
- }
- return new MetallicRoughness
- {
- baseColor = baseColor,
- opacity = opacity,
- metallic = metallic,
- roughness = 1 - glossiness
- };
- }
- private float solveMetallic(float diffuse, float specular, float oneMinusSpecularStrength)
- {
- if (specular < dielectricSpecular.r)
- {
- return 0;
- }
- var a = dielectricSpecular.r;
- var b = diffuse * oneMinusSpecularStrength / (1 - dielectricSpecular.r) + specular - 2 * dielectricSpecular.r;
- var c = dielectricSpecular.r - specular;
- var D = b * b - 4 * a * c;
- return ClampScalar((float)(-b + Math.Sqrt(D)) / (2 * a), 0, 1);
- }
- /**
- * Returns the value itself if it's between min and max.
- * Returns min if the value is lower than min.
- * Returns max if the value is greater than max.
- */
- private static float ClampScalar(float value, float min = 0, float max = 1)
- {
- return Math.Min(max, Math.Max(min, value));
- }
- private class SpecularGlossiness
- {
- public BabylonColor3 diffuse;
- public float opacity;
- public BabylonColor3 specular;
- public float glossiness;
- }
- private class MetallicRoughness
- {
- public BabylonColor3 baseColor;
- public float opacity;
- public float metallic;
- public float roughness;
- }
- }
- }
|