private BabylonTexture ExportSpecularTexture(IIGameMaterial materialNode, float[] specularColor, BabylonScene babylonScene)
        {
            ITexmap specularColorTexMap = _getTexMap(materialNode, 2);
            ITexmap specularLevelTexMap = _getTexMap(materialNode, 3);

            // --- Babylon texture ---

            var specularColorTexture = _getBitmapTex(specularColorTexMap);
            var specularLevelTexture = _getBitmapTex(specularLevelTexMap);

            if (specularLevelTexture == null)
            {
                // Copy specular color image
                // Assume specular color texture is already pre-multiplied by a global specular level value
                // So do not use global specular level
                return(ExportTexture(specularColorTexture, babylonScene));
            }

            // Use one as a reference for UVs parameters
            var texture = specularColorTexture != null ? specularColorTexture : specularLevelTexture;

            if (texture == null)
            {
                return(null);
            }

            RaiseMessage("Multiply specular color and level textures", 2);

            string nameText = null;

            nameText = (specularColorTexture != null ? Path.GetFileNameWithoutExtension(specularColorTexture.Map.FullFilePath) : TextureUtilities.ColorToStringName(specularColor)) +
                       Path.GetFileNameWithoutExtension(specularLevelTexture.Map.FullFilePath) + "_specularColor";

            var textureID = texture.GetGuid().ToString();

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }
            else
            {
                var babylonTexture = new BabylonTexture(textureID)
                {
                    name = nameText + ".jpg" // TODO - unsafe name, may conflict with another texture name
                };

                // Level
                babylonTexture.level = 1.0f;

                // UVs
                var uvGen = _exportUV(texture.UVGen, babylonTexture);

                // Is cube
                _exportIsCube(texture.Map.FullFilePath, babylonTexture, false);


                // --- Multiply specular color and level maps ---

                // Alpha
                babylonTexture.hasAlpha        = false;
                babylonTexture.getAlphaFromRGB = false;

                if (exportParameters.writeTextures)
                {
                    // Load bitmaps
                    var specularColorBitmap = _loadTexture(specularColorTexMap);
                    var specularLevelBitmap = _loadTexture(specularLevelTexMap);

                    if (specularLevelBitmap == null)
                    {
                        // Copy specular color image
                        RaiseError("Failed to load specular level texture. Specular color is exported alone.", 3);
                        return(ExportTexture(specularColorTexture, babylonScene));
                    }

                    // Retreive dimensions
                    int width              = 0;
                    int height             = 0;
                    var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, specularColorBitmap, specularLevelBitmap);
                    if (!haveSameDimensions)
                    {
                        RaiseError("Specular color and specular level maps should have same dimensions", 3);
                    }

                    // Create pre-multiplied specular color map
                    var _specularColor = Color.FromArgb(
                        (int)(specularColor[0] * 255),
                        (int)(specularColor[1] * 255),
                        (int)(specularColor[2] * 255));
                    Bitmap specularColorPreMultipliedBitmap = new Bitmap(width, height);
                    for (int x = 0; x < width; x++)
                    {
                        for (int y = 0; y < height; y++)
                        {
                            var specularColorAtPixel = specularColorBitmap != null?specularColorBitmap.GetPixel(x, y) : _specularColor;

                            var specularLevelAtPixel = specularLevelBitmap.GetPixel(x, y);

                            var specularColorPreMultipliedAtPixel = specularColorAtPixel.multiply(specularLevelAtPixel);

                            specularColorPreMultipliedBitmap.SetPixel(x, y, specularColorPreMultipliedAtPixel);
                        }
                    }

                    // Write bitmap
                    if (isBabylonExported)
                    {
                        RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3);
                        TextureUtilities.SaveBitmap(specularColorPreMultipliedBitmap, babylonScene.OutputPath, babylonTexture.name, ImageFormat.Jpeg, exportParameters.txtQuality, this);
                    }
                    else
                    {
                        // Store created bitmap for further use in gltf export
                        babylonTexture.bitmap = specularColorPreMultipliedBitmap;
                    }
                }
                textureMap.Add(babylonTexture.Id, babylonTexture);
                return(babylonTexture);
            }
        }
        private GLTFTextureInfo ExportEmissiveTexture(BabylonStandardMaterial babylonMaterial, GLTF gltf, float[] defaultEmissive, float[] defaultDiffuse)
        {
            // Use one as a reference for UVs parameters
            var babylonTexture = babylonMaterial.emissiveTexture != null ? babylonMaterial.emissiveTexture : babylonMaterial.diffuseTexture;

            if (babylonTexture == null)
            {
                return(null);
            }

            // Anticipate if a black texture is going to be export
            if (babylonMaterial.emissiveTexture == null && defaultEmissive.IsAlmostEqualTo(new float[] { 0, 0, 0 }, 0))
            {
                return(null);
            }

            // Check if the texture has already been exported
            if (GetRegisteredEmissive(babylonMaterial, defaultDiffuse, defaultEmissive) != null)
            {
                return(GetRegisteredEmissive(babylonMaterial, defaultDiffuse, defaultEmissive));
            }

            Bitmap emissivePremultipliedBitmap = null;

            if (exportParameters.writeTextures)
            {
                // Emissive
                Bitmap emissiveBitmap = null;
                if (babylonMaterial.emissiveTexture != null)
                {
                    emissiveBitmap = TextureUtilities.LoadTexture(babylonMaterial.emissiveTexture.originalPath, logger);
                }

                // Diffuse
                Bitmap diffuseBitmap = null;
                if (babylonMaterial.diffuseTexture != null)
                {
                    diffuseBitmap = TextureUtilities.LoadTexture(babylonMaterial.diffuseTexture.originalPath, logger);
                }

                if (emissiveBitmap != null || diffuseBitmap != null)
                {
                    // Retreive dimensions
                    int width              = 0;
                    int height             = 0;
                    var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, emissiveBitmap, diffuseBitmap);
                    if (!haveSameDimensions)
                    {
                        logger.RaiseError("Emissive and diffuse maps should have same dimensions", 2);
                    }

                    // Create pre-multiplied emissive map
                    emissivePremultipliedBitmap = new Bitmap(width, height);
                    for (int x = 0; x < width; x++)
                    {
                        for (int y = 0; y < height; y++)
                        {
                            var _emissive = emissiveBitmap != null?emissiveBitmap.GetPixel(x, y).toArrayRGB().Multiply(1f / 255.0f) : defaultEmissive;

                            var _diffuse = diffuseBitmap != null?diffuseBitmap.GetPixel(x, y).toArrayRGB().Multiply(1f / 255.0f) : defaultDiffuse;

                            var emissivePremultiplied = _emissive.Multiply(_diffuse);

                            Color colorEmissivePremultiplied = Color.FromArgb(
                                (int)(emissivePremultiplied[0] * 255),
                                (int)(emissivePremultiplied[1] * 255),
                                (int)(emissivePremultiplied[2] * 255)
                                );
                            emissivePremultipliedBitmap.SetPixel(x, y, colorEmissivePremultiplied);
                        }
                    }
                }
            }

            var emissiveTextureInfo = ExportBitmapTexture(gltf, babylonTexture, emissivePremultipliedBitmap);

            // Register the texture for optimisation
            RegisterEmissive(emissiveTextureInfo, babylonMaterial, defaultDiffuse, defaultEmissive);

            return(emissiveTextureInfo);
        }
        private BabylonTexture ExportORMTexture(ITexmap ambientOcclusionTexMap, ITexmap roughnessTexMap, ITexmap metallicTexMap, float metallic, float roughness, BabylonScene babylonScene, bool invertRoughness)
        {
            // --- Babylon texture ---

            var metallicTexture         = _getBitmapTex(metallicTexMap);
            var roughnessTexture        = _getBitmapTex(roughnessTexMap);
            var ambientOcclusionTexture = _getBitmapTex(ambientOcclusionTexMap);

            // Use metallic or roughness texture as a reference for UVs parameters
            var texture = metallicTexture != null ? metallicTexture : roughnessTexture;

            if (texture == null)
            {
                return(null);
            }

            RaiseMessage("Export ORM texture", 2);

            var textureID = texture.GetGuid().ToString();

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }
            else
            {
                var babylonTexture = new BabylonTexture(textureID)
                {
                    name = (ambientOcclusionTexMap != null ? Path.GetFileNameWithoutExtension(ambientOcclusionTexture.Map.FileName) : "") +
                           (roughnessTexMap != null ? Path.GetFileNameWithoutExtension(roughnessTexture.Map.FileName) : ("" + (int)(roughness * 255))) +
                           (metallicTexMap != null ? Path.GetFileNameWithoutExtension(metallicTexture.Map.FileName) : ("" + (int)(metallic * 255))) + ".jpg" // TODO - unsafe name, may conflict with another texture name
                };

                // UVs
                var uvGen = _exportUV(texture.UVGen, babylonTexture);

                // Is cube
                _exportIsCube(texture.Map.FullFilePath, babylonTexture, false);


                // --- Merge metallic and roughness maps ---

                if (!isTextureOk(metallicTexMap) && !isTextureOk(roughnessTexMap))
                {
                    return(null);
                }

                if (exportParameters.writeTextures)
                {
                    // Load bitmaps
                    var metallicBitmap         = _loadTexture(metallicTexMap);
                    var roughnessBitmap        = _loadTexture(roughnessTexMap);
                    var ambientOcclusionBitmap = _loadTexture(ambientOcclusionTexMap);

                    // Retreive dimensions
                    int width              = 0;
                    int height             = 0;
                    var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, metallicBitmap, roughnessBitmap, ambientOcclusionBitmap);
                    if (!haveSameDimensions)
                    {
                        RaiseError((ambientOcclusionBitmap != null ? "Occlusion, roughness and metallic " : "Metallic and roughness") + " maps should have same dimensions", 3);
                    }

                    // Create ORM map
                    Bitmap ormBitmap = new Bitmap(width, height);
                    for (int x = 0; x < width; x++)
                    {
                        for (int y = 0; y < height; y++)
                        {
                            int _occlusion = ambientOcclusionBitmap != null?ambientOcclusionBitmap.GetPixel(x, y).R : 0;

                            int _roughness = roughnessBitmap != null ? (invertRoughness ? 255 - roughnessBitmap.GetPixel(x, y).G : roughnessBitmap.GetPixel(x, y).G) : (int)(roughness * 255.0f);
                            int _metallic  = metallicBitmap != null?metallicBitmap.GetPixel(x, y).B : (int)(metallic * 255.0f);

                            // The occlusion values are sampled from the R channel.
                            // The roughness values are sampled from the G channel.
                            // The metalness values are sampled from the B channel.
                            Color colorMetallicRoughness = Color.FromArgb(_occlusion, _roughness, _metallic);
                            ormBitmap.SetPixel(x, y, colorMetallicRoughness);
                        }
                    }

                    // Write bitmap
                    if (isBabylonExported)
                    {
                        RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3);
                        TextureUtilities.SaveBitmap(ormBitmap, babylonScene.OutputPath, babylonTexture.name, ImageFormat.Jpeg, exportParameters.txtQuality, this);
                    }
                    else
                    {
                        // Store created bitmap for further use in gltf export
                        babylonTexture.bitmap = ormBitmap;
                    }
                }
                textureMap[babylonTexture.Id] = babylonTexture;
                return(babylonTexture);
            }
        }
        /// <returns></returns>
        private BabylonTexture ExportBaseColorAlphaTexture(ITexmap baseColorTexMap, ITexmap alphaTexMap, float[] baseColor, float alpha, BabylonScene babylonScene, string materialName, bool isOpacity = false)
        {
            // --- Babylon texture ---

            var baseColorTexture = _getBitmapTex(baseColorTexMap);
            var alphaTexture     = _getBitmapTex(alphaTexMap);

            var texture = baseColorTexture != null ? baseColorTexture : alphaTexture;

            if (texture == null)
            {
                return(null);
            }

            var baseColorTextureMapExtension = Path.GetExtension(baseColorTexture.Map.FullFilePath).ToLower();

            if (alphaTexture == null && baseColorTexture != null && alpha == 1)
            {
                if (baseColorTexture.AlphaSource == 0 &&
                    (baseColorTextureMapExtension == ".tif" || baseColorTextureMapExtension == ".tiff"))
                {
                    RaiseWarning($"Diffuse texture named {baseColorTexture.Map.FullFilePath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 3);
                    RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 3);
                }


                if (baseColorTexture.AlphaSource == 3 && // 'None (Opaque)'
                    baseColorTextureMapExtension == ".jpg" || baseColorTextureMapExtension == ".jpeg" || baseColorTextureMapExtension == ".bmp" || baseColorTextureMapExtension == ".png")
                {
                    // Copy base color image
                    return(ExportTexture(baseColorTexture, babylonScene));
                }
            }

            // Use one as a reference for UVs parameters


            RaiseMessage("Export baseColor+Alpha texture", 2);

            string nameText = null;

            nameText = (baseColorTexture != null ? Path.GetFileNameWithoutExtension(baseColorTexture.Map.FullFilePath) : TextureUtilities.ColorToStringName(baseColor));

            var textureID = texture.GetGuid().ToString();

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }
            else
            {
                var babylonTexture = new BabylonTexture(textureID)
                {
                    name = nameText // TODO - unsafe name, may conflict with another texture name
                };

                // Level
                babylonTexture.level = 1.0f;

                // UVs
                var uvGen = _exportUV(texture.UVGen, babylonTexture);

                // Is cube
                _exportIsCube(texture.Map.FullFilePath, babylonTexture, false);


                // --- Merge baseColor and alpha maps ---

                var hasBaseColor = isTextureOk(baseColorTexMap);
                var hasAlpha     = isTextureOk(alphaTexMap);

                // Alpha

                // If the texture file format does not traditionally support an alpha channel, export the base texture as opaque
                if (baseColorTextureMapExtension == ".jpg" || baseColorTextureMapExtension == ".jpeg" || baseColorTextureMapExtension == ".bmp")
                {
                    babylonTexture.hasAlpha = false;
                }
                else
                {
                    babylonTexture.hasAlpha = isTextureOk(alphaTexMap) || (isTextureOk(baseColorTexMap) && baseColorTexture.AlphaSource == 0) || alpha < 1.0f;
                }
                babylonTexture.getAlphaFromRGB = false;
                if ((!isTextureOk(alphaTexMap) && alpha == 1.0f && (isTextureOk(baseColorTexMap) && baseColorTexture.AlphaSource == 0)) &&
                    (baseColorTextureMapExtension == ".tif" || baseColorTextureMapExtension == ".tiff"))
                {
                    RaiseWarning($"Diffuse texture named {baseColorTexture.Map.FullFilePath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 3);
                    RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 3);
                }

                if (!hasBaseColor && !hasAlpha)
                {
                    return(null);
                }

                // Set image format
                ImageFormat imageFormat = babylonTexture.hasAlpha ? ImageFormat.Png : ImageFormat.Jpeg;
                babylonTexture.name += imageFormat == ImageFormat.Png ? ".png" : ".jpg";

                // --- Merge baseColor and alpha maps ---

                if (exportParameters.writeTextures)
                {
                    // Load bitmaps
                    var baseColorBitmap = _loadTexture(baseColorTexMap);
                    var alphaBitmap     = _loadTexture(alphaTexMap);

                    // Retreive dimensions
                    int width              = 0;
                    int height             = 0;
                    var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, baseColorBitmap, alphaBitmap);
                    if (!haveSameDimensions)
                    {
                        RaiseError("Base color and transparency color maps should have same dimensions", 3);
                    }

                    var getAlphaFromRGB = alphaTexture != null && ((alphaTexture.AlphaSource == 2) || (alphaTexture.AlphaSource == 3)); // 'RGB intensity' or 'None (Opaque)'

                    // Create baseColor+alpha map
                    var _baseColor = Color.FromArgb(
                        (int)(baseColor[0] * 255),
                        (int)(baseColor[1] * 255),
                        (int)(baseColor[2] * 255));
                    var    _alpha = (int)(alpha * 255);
                    Bitmap baseColorAlphaBitmap = new Bitmap(width, height);
                    for (int x = 0; x < width; x++)
                    {
                        for (int y = 0; y < height; y++)
                        {
                            var baseColorAtPixel = baseColorBitmap != null?baseColorBitmap.GetPixel(x, y) : _baseColor;

                            Color baseColorAlpha;
                            if (alphaBitmap != null)
                            {
                                // Retreive alpha from alpha texture
                                Color alphaColor   = alphaBitmap.GetPixel(x, y);
                                int   alphaAtPixel = getAlphaFromRGB ? alphaColor.R : alphaColor.A;
                                if (isOpacity == false)
                                {
                                    // Convert transparency to opacity
                                    alphaAtPixel = 255 - alphaAtPixel;
                                }
                                baseColorAlpha = Color.FromArgb(alphaAtPixel, baseColorAtPixel);
                            }
                            else if (baseColorTexture != null && baseColorTexture.AlphaSource == 0) // Alpha source is 'Image Alpha'
                            {
                                // Use all channels from base color
                                baseColorAlpha = baseColorAtPixel;
                            }
                            else
                            {
                                // Use RGB channels from base color and default alpha
                                baseColorAlpha = Color.FromArgb(_alpha, baseColorAtPixel.R, baseColorAtPixel.G, baseColorAtPixel.B);
                            }
                            baseColorAlphaBitmap.SetPixel(x, y, baseColorAlpha);
                        }
                    }

                    // Write bitmap
                    if (isBabylonExported)
                    {
                        RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3);
                        TextureUtilities.SaveBitmap(baseColorAlphaBitmap, babylonScene.OutputPath, babylonTexture.name, imageFormat, exportParameters.txtQuality, this);
                    }
                    else
                    {
                        // Store created bitmap for further use in gltf export
                        babylonTexture.bitmap = baseColorAlphaBitmap;
                    }
                }

                return(babylonTexture);
            }
        }
        private BabylonTexture ExportClearCoatTexture(ITexmap intensityTexMap, ITexmap roughnessTexMap, float coatWeight, float coatRoughness, BabylonScene babylonScene, string materialName, bool invertRoughness)
        {
            // --- Babylon texture ---
            var intensityTexture = _getBitmapTex(intensityTexMap);
            var roughnessTexture = _getBitmapTex(roughnessTexMap);

            var texture = intensityTexture != null ? intensityTexture : roughnessTexture;

            if (texture == null)
            {
                return(null);
            }

            // Use one as a reference for UVs parameters

            RaiseMessage("Export Clear Coat weight+roughness texture", 2);

            string nameText = Path.GetFileNameWithoutExtension(texture.Map.FullFilePath);

            var textureID = texture.GetGuid().ToString();

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }
            else
            {
                var babylonTexture = new BabylonTexture(textureID)
                {
                    name = nameText // TODO - unsafe name, may conflict with another texture name
                };

                // Level
                babylonTexture.level = 1.0f;

                // UVs
                var uvGen = _exportUV(texture.UVGen, babylonTexture);

                // Is cube
                _exportIsCube(texture.Map.FullFilePath, babylonTexture, false);

                // --- Merge maps ---
                var hasIntensity = isTextureOk(intensityTexture);
                var hasRoughness = isTextureOk(roughnessTexture);
                if (!hasIntensity && !hasRoughness)
                {
                    return(null);
                }

                // Set image format
                ImageFormat imageFormat = ImageFormat.Jpeg;
                babylonTexture.name += ".jpg";

                if (exportParameters.writeTextures)
                {
                    // Load bitmaps
                    var intensityBitmap = _loadTexture(intensityTexture);
                    var roughnessBitmap = _loadTexture(roughnessTexture);

                    // Retreive dimensions
                    int width              = 0;
                    int height             = 0;
                    var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, intensityBitmap, roughnessBitmap);
                    if (!haveSameDimensions)
                    {
                        RaiseError("Base color and transparency color maps should have same dimensions", 3);
                    }

                    // Create map
                    var    _intensity = (int)(coatWeight * 255);
                    var    _roughness = (int)(coatRoughness * 255);
                    Bitmap intensityRoughnessBitmap = new Bitmap(width, height);
                    for (int x = 0; x < width; x++)
                    {
                        for (int y = 0; y < height; y++)
                        {
                            var intensityAtPixel = (intensityBitmap == null) ? _intensity : intensityBitmap.GetPixel(x, y).R;

                            Color intensityRoughness;
                            if (roughnessBitmap == null)
                            {
                                intensityRoughness = Color.FromArgb(intensityAtPixel, _roughness, 0);
                            }
                            else
                            {
                                var roughnessAtPixel = (roughnessBitmap == null) ?
                                                       _roughness :
                                                       invertRoughness ? 255 - roughnessBitmap.GetPixel(x, y).G : roughnessBitmap.GetPixel(x, y).G;

                                intensityRoughness = Color.FromArgb(intensityAtPixel, roughnessAtPixel, 0);
                            }
                            intensityRoughnessBitmap.SetPixel(x, y, intensityRoughness);
                        }
                    }

                    // Write bitmap
                    if (isBabylonExported)
                    {
                        RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3);
                        TextureUtilities.SaveBitmap(intensityRoughnessBitmap, babylonScene.OutputPath, babylonTexture.name, imageFormat, exportParameters.txtQuality, this);
                    }
                    else
                    {
                        // Store created bitmap for further use in gltf export
                        babylonTexture.bitmap = intensityRoughnessBitmap;
                    }
                }

                return(babylonTexture);
            }
        }
Exemple #6
0
        private void ExportMaterial(BabylonMaterial babylonMaterial, GLTF gltf)
        {
            var name = babylonMaterial.name;
            var id   = babylonMaterial.id;

            logger.RaiseMessage("GLTFExporter.Material | Export material named: " + name, 1);

            GLTFMaterial          gltfMaterial           = null;
            string                message                = null;
            IGLTFMaterialExporter customMaterialExporter = exportParameters.customGLTFMaterialExporter;

            if (customMaterialExporter != null && customMaterialExporter.GetGltfMaterial(babylonMaterial, gltf, logger, out gltfMaterial))
            {
                gltfMaterial.index = gltf.MaterialsList.Count;
                gltf.MaterialsList.Add(gltfMaterial);
            }
            else if (babylonMaterial.GetType() == typeof(BabylonStandardMaterial))
            {
                var babylonStandardMaterial = babylonMaterial as BabylonStandardMaterial;


                // --- prints ---
                #region prints

                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial data", 2);
                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial.alphaMode=" + babylonMaterial.alphaMode, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);

                // Ambient
                for (int i = 0; i < babylonStandardMaterial.ambient.Length; i++)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.ambient[" + i + "]=" + babylonStandardMaterial.ambient[i], 3);
                }

                // Diffuse
                logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.diffuse.Length=" + babylonStandardMaterial.diffuse.Length, 3);
                for (int i = 0; i < babylonStandardMaterial.diffuse.Length; i++)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.diffuse[" + i + "]=" + babylonStandardMaterial.diffuse[i], 3);
                }
                if (babylonStandardMaterial.diffuseTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.diffuseTexture=null", 3);
                }
                else
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.diffuseTexture.name=" + babylonStandardMaterial.diffuseTexture.name, 3);
                }

                // Normal / bump
                if (babylonStandardMaterial.bumpTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.bumpTexture=null", 3);
                }
                else
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.bumpTexture.name=" + babylonStandardMaterial.bumpTexture.name, 3);
                }

                // Opacity
                if (babylonStandardMaterial.opacityTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.opacityTexture=null", 3);
                }
                else
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.opacityTexture.name=" + babylonStandardMaterial.opacityTexture.name, 3);
                }

                // Specular
                for (int i = 0; i < babylonStandardMaterial.specular.Length; i++)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.specular[" + i + "]=" + babylonStandardMaterial.specular[i], 3);
                }
                logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.specularPower=" + babylonStandardMaterial.specularPower, 3);
                if (babylonStandardMaterial.specularTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.specularTexture=null", 3);
                }
                else
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.specularTexture.name=" + babylonStandardMaterial.specularTexture.name, 3);
                }

                // Occlusion
                if (babylonStandardMaterial.ambientTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.ambientTexture=null", 3);
                }
                else
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.ambientTexture.name=" + babylonStandardMaterial.ambientTexture.name, 3);
                }

                // Emissive
                for (int i = 0; i < babylonStandardMaterial.emissive.Length; i++)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.emissive[" + i + "]=" + babylonStandardMaterial.emissive[i], 3);
                }
                if (babylonStandardMaterial.emissiveTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.emissiveTexture=null", 3);
                }
                else
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonStandardMaterial.emissiveTexture.name=" + babylonStandardMaterial.emissiveTexture.name, 3);
                }
                #endregion


                // --------------------------------
                // --------- gltfMaterial ---------
                // --------------------------------

                logger.RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
                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;
                // linkEmissiveWithDiffuse attribute doesn't have an equivalent in gltf format
                // When true, the emissive texture needs to be manually multiplied with diffuse texture
                // Otherwise, the emissive texture is assumed to be already pre-multiplied
                if (babylonStandardMaterial.linkEmissiveWithDiffuse)
                {
                    // Even when no emissive texture is provided, the self illumination value needs to be multiplied to the diffuse texture in order to get the pre-multiplied emissive (texture)
                    if (babylonStandardMaterial.emissiveTexture != null || babylonStandardMaterial.selfIllum > 0)
                    {
                        // Default emissive is the raw value of the self illumination
                        // It is not the babylon emissive value which is already pre-multiplied with diffuse color
                        float[] defaultEmissive = new float[] { 1, 1, 1 }.Multiply(babylonStandardMaterial.selfIllum);
                        gltfMaterial.emissiveTexture = ExportEmissiveTexture(babylonStandardMaterial, gltf, defaultEmissive, babylonStandardMaterial.diffuse);
                    }
                }
                else
                {
                    gltfMaterial.emissiveTexture = ExportTexture(babylonStandardMaterial.emissiveTexture, gltf);
                }

                // Constraints
                if (gltfMaterial.emissiveTexture != null)
                {
                    gltfMaterial.emissiveFactor = new[] { 1.0f, 1.0f, 1.0f };
                }

                // --------------------------------
                // --- gltfPbrMetallicRoughness ---
                // --------------------------------

                logger.RaiseMessage("GLTFExporter.Material | create gltfPbrMetallicRoughness", 2);
                var gltfPbrMetallicRoughness = new GLTFPBRMetallicRoughness();
                gltfMaterial.pbrMetallicRoughness = gltfPbrMetallicRoughness;

                // --- Global ---

                // Eye Ball correction to limit overall brightness from std to PBR.
                // This only impacts the factors.
                var correctedDiffuse = new BabylonColor3(babylonStandardMaterial.diffuse).scale(0.5f);

                SpecularGlossiness _specularGlossiness = new SpecularGlossiness
                {
                    diffuse    = correctedDiffuse,
                    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 ---
                var babylonTexture = babylonStandardMaterial.diffuseTexture != null ? babylonStandardMaterial.diffuseTexture :
                                     babylonStandardMaterial.specularTexture != null ? babylonStandardMaterial.specularTexture :
                                     babylonStandardMaterial.opacityTexture != null ? babylonStandardMaterial.opacityTexture :
                                     null;

                if (babylonTexture != null)
                {
                    //Check if the texture already exist
                    var _key = SetStandText(babylonStandardMaterial);

                    if (GetStandTextInfo(_key) != null)
                    {
                        var _pairBCMR = GetStandTextInfo(_key);
                        gltfPbrMetallicRoughness.baseColorTexture         = _pairBCMR.baseColor;
                        gltfPbrMetallicRoughness.metallicRoughnessTexture = _pairBCMR.metallicRoughness;
                    }
                    else
                    {
                        bool isAlphaInTexture = (isTextureOk(babylonStandardMaterial.diffuseTexture) && babylonStandardMaterial.diffuseTexture.hasAlpha) ||
                                                isTextureOk(babylonStandardMaterial.opacityTexture);

                        Bitmap baseColorBitmap         = null;
                        Bitmap metallicRoughnessBitmap = null;

                        GLTFTextureInfo textureInfoBC = new GLTFTextureInfo();
                        GLTFTextureInfo textureInfoMR = new GLTFTextureInfo();

                        if (exportParameters.writeTextures)
                        {
                            // Diffuse
                            Bitmap diffuseBitmap = null;
                            if (babylonStandardMaterial.diffuseTexture != null)
                            {
                                diffuseBitmap = TextureUtilities.LoadTexture(babylonStandardMaterial.diffuseTexture.originalPath, logger);
                            }

                            // Specular
                            Bitmap specularBitmap = null;
                            if (babylonStandardMaterial.specularTexture != null)
                            {
                                if (babylonStandardMaterial.specularTexture.bitmap != null)
                                {
                                    // Specular color map has been computed by the exporter
                                    specularBitmap = babylonStandardMaterial.specularTexture.bitmap;
                                }
                                else
                                {
                                    // Specular color map is straight input
                                    specularBitmap = TextureUtilities.LoadTexture(babylonStandardMaterial.specularTexture.originalPath, logger);
                                }
                            }

                            // Opacity / Alpha / Transparency
                            Bitmap opacityBitmap = null;
                            if ((babylonStandardMaterial.diffuseTexture == null || babylonStandardMaterial.diffuseTexture.hasAlpha == false) && babylonStandardMaterial.opacityTexture != null)
                            {
                                opacityBitmap = TextureUtilities.LoadTexture(babylonStandardMaterial.opacityTexture.originalPath, logger);
                            }

                            if (diffuseBitmap != null || specularBitmap != null || opacityBitmap != null)
                            {
                                // Retreive dimensions
                                int width              = 0;
                                int height             = 0;
                                var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, diffuseBitmap, specularBitmap, opacityBitmap);
                                if (!haveSameDimensions)
                                {
                                    logger.RaiseError("Diffuse, specular and opacity maps should have same dimensions", 2);
                                }

                                // Create baseColor+alpha and metallic+roughness maps
                                baseColorBitmap         = new Bitmap(width, height);
                                metallicRoughnessBitmap = new Bitmap(width, height);
                                for (int x = 0; x < width; x++)
                                {
                                    for (int y = 0; y < height; y++)
                                    {
                                        SpecularGlossiness specularGlossinessTexture = new SpecularGlossiness
                                        {
                                            diffuse = diffuseBitmap != null ? new BabylonColor3(diffuseBitmap.GetPixel(x, y)) :
                                                      _specularGlossiness.diffuse,
                                            opacity = diffuseBitmap != null && babylonStandardMaterial.diffuseTexture.hasAlpha ? diffuseBitmap.GetPixel(x, y).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 :
                                                      _specularGlossiness.opacity,
                                            specular = specularBitmap != null ? new BabylonColor3(specularBitmap.GetPixel(x, y)) :
                                                       _specularGlossiness.specular,
                                            glossiness = babylonStandardMaterial.useGlossinessFromSpecularMapAlpha && specularBitmap != null?specularBitmap.GetPixel(x, y).A / 255.0f :
                                                         _specularGlossiness.glossiness
                                        };

                                        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);

                                        // 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 textures
                        if (baseColorBitmap != null || babylonTexture.bitmap != null)
                        {
                            textureInfoBC = ExportBitmapTexture(gltf, babylonTexture, baseColorBitmap);
                            gltfPbrMetallicRoughness.baseColorTexture = textureInfoBC;
                        }

                        if (isTextureOk(babylonStandardMaterial.specularTexture))
                        {
                            textureInfoMR = ExportBitmapTexture(gltf, babylonTexture, metallicRoughnessBitmap);
                            gltfPbrMetallicRoughness.metallicRoughnessTexture = textureInfoMR;
                        }

                        //register the texture
                        AddStandText(_key, textureInfoBC, textureInfoMR);
                    }

                    // Constraints
                    if (gltfPbrMetallicRoughness.baseColorTexture != null)
                    {
                        gltfPbrMetallicRoughness.baseColorFactor = new[] { 1.0f, 1.0f, 1.0f, 1.0f };
                    }

                    if (gltfPbrMetallicRoughness.metallicRoughnessTexture != null)
                    {
                        gltfPbrMetallicRoughness.metallicFactor  = 1.0f;
                        gltfPbrMetallicRoughness.roughnessFactor = 1.0f;
                    }
                }
            }
            else if (babylonMaterial.GetType() == typeof(BabylonPBRMetallicRoughnessMaterial))
            {
                var babylonPBRMetallicRoughnessMaterial = babylonMaterial as BabylonPBRMetallicRoughnessMaterial;
                // --- prints ---
                #region prints

                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial data", 2);
                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial.alphaMode=" + babylonMaterial.alphaMode, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);

                // Global
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.maxSimultaneousLights=" + babylonPBRMetallicRoughnessMaterial.maxSimultaneousLights, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.disableLighting=" + babylonPBRMetallicRoughnessMaterial.disableLighting, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.alphaCutOff=" + babylonPBRMetallicRoughnessMaterial.alphaCutOff, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.transparencyMode=" + babylonPBRMetallicRoughnessMaterial.transparencyMode, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.doubleSided=" + babylonPBRMetallicRoughnessMaterial.doubleSided, 3);

                // Base color
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseColor.Length=" + babylonPBRMetallicRoughnessMaterial.baseColor.Length, 3);
                for (int i = 0; i < babylonPBRMetallicRoughnessMaterial.baseColor.Length; i++)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseColor[" + i + "]=" + babylonPBRMetallicRoughnessMaterial.baseColor[i], 3);
                }
                if (babylonPBRMetallicRoughnessMaterial.baseTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseTexture=null", 3);
                }

                // Metallic+roughness
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallic=" + babylonPBRMetallicRoughnessMaterial.metallic, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.roughness=" + babylonPBRMetallicRoughnessMaterial.roughness, 3);
                if (babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture=null", 3);
                }

                // Normal / bump
                if (babylonPBRMetallicRoughnessMaterial.normalTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.normalTexture=null", 3);
                }
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.invertNormalMapX=" + babylonPBRMetallicRoughnessMaterial.invertNormalMapX, 3);
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.invertNormalMapY=" + babylonPBRMetallicRoughnessMaterial.invertNormalMapY, 3);

                // Emissive
                for (int i = 0; i < babylonPBRMetallicRoughnessMaterial.emissive.Length; i++)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.emissiveColor[" + i + "]=" + babylonPBRMetallicRoughnessMaterial.emissive[i], 3);
                }
                if (babylonPBRMetallicRoughnessMaterial.emissiveTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.emissiveTexture=null", 3);
                }

                // Ambient occlusion
                logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.occlusionStrength=" + babylonPBRMetallicRoughnessMaterial.occlusionStrength, 3);
                if (babylonPBRMetallicRoughnessMaterial.occlusionTexture == null)
                {
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.occlusionTexture=null", 3);
                }
                #endregion


                // --------------------------------
                // --------- gltfMaterial ---------
                // --------------------------------

                logger.RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
                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);

                // Occlusion
                if (babylonPBRMetallicRoughnessMaterial.occlusionTexture != null)
                {
                    if (babylonPBRMetallicRoughnessMaterial.occlusionTexture.bitmap != null)
                    {
                        // ORM texture has been merged manually by the exporter
                        // Occlusion is defined as well as metallic and/or roughness
                        logger.RaiseVerbose("Occlusion is defined as well as metallic and/or roughness", 2);
                        gltfMaterial.occlusionTexture = ExportBitmapTexture(gltf, babylonPBRMetallicRoughnessMaterial.occlusionTexture);
                    }
                    else
                    {
                        // ORM texture was already merged or only occlusion is defined
                        logger.RaiseVerbose("ORM texture was already merged or only occlusion is defined", 2);
                        gltfMaterial.occlusionTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.occlusionTexture, gltf);
                    }
                }

                // Emissive
                gltfMaterial.emissiveFactor  = babylonPBRMetallicRoughnessMaterial.emissive;
                gltfMaterial.emissiveTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.emissiveTexture, gltf);


                // --------------------------------
                // --- gltfPbrMetallicRoughness ---
                // --------------------------------

                logger.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],
                    babylonPBRMetallicRoughnessMaterial.alpha
                };
                if (babylonPBRMetallicRoughnessMaterial.baseTexture != null)
                {
                    if (babylonPBRMetallicRoughnessMaterial.baseTexture.bitmap != null)
                    {
                        gltfPbrMetallicRoughness.baseColorTexture = ExportBitmapTexture(gltf, babylonPBRMetallicRoughnessMaterial.baseTexture);
                    }
                    else
                    {
                        gltfPbrMetallicRoughness.baseColorTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.baseTexture, gltf);
                    }
                }

                // Metallic roughness
                gltfPbrMetallicRoughness.metallicFactor  = babylonPBRMetallicRoughnessMaterial.metallic;
                gltfPbrMetallicRoughness.roughnessFactor = babylonPBRMetallicRoughnessMaterial.roughness;
                if (babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture != null)
                {
                    if (babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture == babylonPBRMetallicRoughnessMaterial.occlusionTexture)
                    {
                        // Occlusion is defined as well as metallic and/or roughness
                        // Use same texture
                        logger.RaiseVerbose("Occlusion is defined as well as metallic and/or roughness", 2);
                        gltfPbrMetallicRoughness.metallicRoughnessTexture = gltfMaterial.occlusionTexture;
                    }
                    else
                    {
                        // Occlusion is not defined, only metallic and/or roughness
                        logger.RaiseVerbose("Occlusion is not defined, only metallic and/or roughness", 2);

                        if (babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture.bitmap != null)
                        {
                            // Metallic & roughness texture has been merged manually by the exporter
                            // Write bitmap file
                            logger.RaiseVerbose("Metallic & roughness texture has been merged manually by the exporter", 2);
                            gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportBitmapTexture(gltf, babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture);
                        }
                        else
                        {
                            // Metallic & roughness texture was already merged
                            // Copy file
                            logger.RaiseVerbose("Metallic & roughness texture was already merged", 2);
                            gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture, gltf);
                        }
                    }
                }
            }
            else
            {
                logger.RaiseWarning("GLTFExporter.Material | Unsupported material type: " + babylonMaterial.GetType(), 2);
            }

            if (gltfMaterial != null && babylonMaterial.isUnlit)
            {
                // Add Unlit extension
                if (!exportParameters.enableKHRMaterialsUnlit)
                {
                    logger.RaiseWarning("GLTFExporter.Material | KHR_materials_unlit has not been enabled for export!", 2);
                }
                else
                {
                    if (gltfMaterial.extensions == null)
                    {
                        gltfMaterial.extensions = new GLTFExtensions();
                    }
                    if (gltf.extensionsUsed == null)
                    {
                        gltf.extensionsUsed = new System.Collections.Generic.List <string>();
                    }
                    if (!gltf.extensionsUsed.Contains("KHR_materials_unlit"))
                    {
                        gltf.extensionsUsed.Add("KHR_materials_unlit");
                    }
                    gltfMaterial.extensions["KHR_materials_unlit"] = new object();
                }
            }

            ExportGLTFExtension(babylonMaterial, ref gltfMaterial, gltf);
        }
Exemple #7
0
        /// <returns></returns>
        private BabylonTexture ExportBaseColorAlphaTexture(ITexmap baseColorTexMap, ITexmap alphaTexMap, float[] baseColor, float alpha, BabylonScene babylonScene, string materialName, bool isOpacity = false)
        {
            // --- Babylon texture ---
            var    baseColorTexture             = _getBitmapTex(baseColorTexMap);
            var    alphaTexture                 = _getBitmapTex(alphaTexMap);
            string baseColorTextureMapExtension = null;

            // If we don't retrieve any textures from Max, return null.
            if (baseColorTexture == null && alphaTexture == null)
            {
                return(null);
            }

            // If we only have a base color texture, and we are using an opaque texture, export the base color image only.
            if (baseColorTexture != null && alphaTexture == null)
            {
                baseColorTextureMapExtension = Path.GetExtension(baseColorTexture.Map.FullFilePath).ToLower();
                if (alpha == 1)
                {
                    if (baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_FILE &&
                        (baseColorTextureMapExtension == ".tif" || baseColorTextureMapExtension == ".tiff"))
                    {
                        RaiseWarning($"Diffuse texture named {baseColorTexture.Map.FullFilePath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 3);
                        RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 3);
                    }

                    // Copy base color image
                    var outTexture = ExportTexture(baseColorTexture, babylonScene);
                    textureMap[outTexture.Id] = outTexture;
                    return(outTexture);
                }
            }

            // Otherwise combine base color and alpha textures to a single output texture
            RaiseMessage("Export baseColor+Alpha texture", 2);

            var hasBaseColor = baseColorTexture != null && isTextureOk(baseColorTexMap);
            var hasAlpha     = isTextureOk(alphaTexMap);
            var texture      = hasBaseColor ? baseColorTexture : alphaTexture;

            ImageFormat imageFormat = null;

            if (hasBaseColor)
            {
                imageFormat = TextureUtilities.GetImageFormat(Path.GetExtension(baseColorTexture.Map.FullFilePath));
            }

            if (hasAlpha || imageFormat == null)
            {
                baseColorTextureMapExtension = ".png"; // since we are adding an alpha channel, export as png. This will convert any other input base texture format to PNG.
                imageFormat = ImageFormat.Png;
            }

            // since we are creating a new texture, give it a unique ID based on the base color and alpha maps.
            var nameText  = (hasBaseColor ? Path.GetFileNameWithoutExtension(baseColorTexture.Map.FullFilePath) + (hasAlpha ?  "_" + Path.GetFileNameWithoutExtension(alphaTexture.Map.FullFilePath) : "") : TextureUtilities.ColorToStringName(baseColor));
            var textureID = hasBaseColor ? texture.GetGuid().ToString() + (hasAlpha ? "_" + alphaTexture.GetGuid().ToString() : "") : string.Format("{0}_{1}", texture.GetGuid().ToString(), nameText);

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }

            BabylonTexture babylonTexture = null;

            babylonTexture = new BabylonTexture(textureID)
            {
                name = nameText
            };

            // Alpha
            babylonTexture.hasAlpha        = hasAlpha || (hasBaseColor && (baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_FILE || baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_RGB)) || alpha < 1.0f;
            babylonTexture.getAlphaFromRGB = false;

            if (!hasBaseColor && !hasAlpha)
            {
                return(null);
            }

            if ((!isTextureOk(alphaTexMap) && alpha == 1.0f && (isTextureOk(baseColorTexMap) && baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_FILE)) &&
                (baseColorTextureMapExtension == ".tif" || baseColorTextureMapExtension == ".tiff"))
            {
                RaiseWarning($"Diffuse texture named {baseColorTexture.Map.FullFilePath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 3);
                RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 3);
            }

            // Set image format

            if (hasAlpha)
            {
                babylonTexture.name += "_alpha_" + alphaTexture.Name;
            }

            if (imageFormat == ImageFormat.Jpeg)
            {
                babylonTexture.name += ".jpg";
            }
            else
            {
                babylonTexture.name += "." + imageFormat.ToString();
            }

            // Level
            babylonTexture.level = 1.0f;

            // UVs
            var uvGen = _exportUV(texture.UVGen, babylonTexture);

            // Is cube
            _exportIsCube(texture.Map.FullFilePath, babylonTexture, false);

            // --- Merge baseColor and alpha maps ---

            if (exportParameters.writeTextures && baseColorTexture != alphaTexture && alphaTexture != null)
            {
                // Load bitmaps
                var baseColorBitmap = _loadTexture(baseColorTexMap);
                var alphaBitmap     = _loadTexture(alphaTexMap);

                // Retreive dimensions
                int width              = 0;
                int height             = 0;
                var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, baseColorBitmap, alphaBitmap);
                if (!haveSameDimensions)
                {
                    RaiseError("Base color and transparency color maps should have same dimensions", 3);
                }

                var getAlphaFromRGB = alphaTexture != null && ((alphaTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_RGB) || (alphaTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_NONE)); // 'RGB intensity' or 'None (Opaque)'

                // Create baseColor+alpha map
                var _baseColor = Color.FromArgb(
                    (int)(baseColor[0] * 255),
                    (int)(baseColor[1] * 255),
                    (int)(baseColor[2] * 255));
                var    _alpha = (int)(alpha * 255);
                Bitmap baseColorAlphaBitmap = new Bitmap(width, height);
                for (int x = 0; x < width; x++)
                {
                    for (int y = 0; y < height; y++)
                    {
                        var baseColorAtPixel = baseColorBitmap != null?baseColorBitmap.GetPixel(x, y) : _baseColor;

                        Color baseColorAlpha;
                        if (alphaBitmap != null)
                        {
                            // Retreive alpha from alpha texture
                            Color alphaColor   = alphaBitmap.GetPixel(x, y);
                            int   alphaAtPixel = getAlphaFromRGB ? alphaColor.R : alphaColor.A;
                            if (isOpacity == false)
                            {
                                // Convert transparency to opacity
                                alphaAtPixel = 255 - alphaAtPixel;
                            }
                            baseColorAlpha = Color.FromArgb(alphaAtPixel, baseColorAtPixel);
                        }
                        else if (baseColorTexture != null && baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_FILE) // Alpha source is 'Image Alpha'
                        {
                            // Use all channels from base color
                            baseColorAlpha = baseColorAtPixel;
                        }
                        else
                        {
                            // Use RGB channels from base color and default alpha
                            baseColorAlpha = Color.FromArgb(_alpha, baseColorAtPixel.R, baseColorAtPixel.G, baseColorAtPixel.B);
                        }
                        baseColorAlphaBitmap.SetPixel(x, y, baseColorAlpha);
                    }
                }

                // Write bitmap
                if (isBabylonExported)
                {
                    RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3);
                    TextureUtilities.SaveBitmap(baseColorAlphaBitmap, babylonScene.OutputPath, babylonTexture.name, imageFormat, exportParameters.txtQuality, this);
                }
                else
                {
                    // Store created bitmap for further use in gltf export
                    babylonTexture.bitmap = baseColorAlphaBitmap;
                }
            }

            return(babylonTexture);
        }