Exemplo n.º 1
0
        // -------------------------
        // --------- Utils ---------
        // -------------------------

        private IBitmapTex _getBitmapTex(ITexmap texMap)
        {
            if (texMap == null || texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                return(null);
            }

            return(texMap.GetParamBlock(0).Owner as IBitmapTex);
        }
        private ITexmap _exportFresnelParameters(ITexmap texMap, out BabylonFresnelParameters fresnelParameters)
        {
            fresnelParameters = null;

            // Fallout
            if (texMap.ClassName == "Falloff") // This is the only way I found to detect it. This is crappy but it works
            {
                RaiseMessage("fresnelParameters", 3);
                fresnelParameters = new BabylonFresnelParameters();

                var paramBlock = texMap.GetParamBlock(0);
                var color1     = paramBlock.GetColor(0, 0, 0);
                var color2     = paramBlock.GetColor(4, 0, 0);

                fresnelParameters.isEnabled  = true;
                fresnelParameters.leftColor  = color2.ToArray();
                fresnelParameters.rightColor = color1.ToArray();

                if (paramBlock.GetInt(8, 0, 0) == 2)
                {
                    fresnelParameters.power = paramBlock.GetFloat(12, 0, 0);
                }
                else
                {
                    fresnelParameters.power = 1;
                }
                var texMap1   = paramBlock.GetTexmap(2, 0, 0);
                var texMap1On = paramBlock.GetInt(3, 0, 0);

                var texMap2   = paramBlock.GetTexmap(6, 0, 0);
                var texMap2On = paramBlock.GetInt(7, 0, 0);

                if (texMap1 != null && texMap1On != 0)
                {
                    texMap = texMap1;
                    fresnelParameters.rightColor = new float[] { 1, 1, 1 };

                    if (texMap2 != null && texMap2On != 0)
                    {
                        RaiseWarning(string.Format("You cannot specify two textures for falloff. Only one is supported"), 3);
                    }
                }
                else if (texMap2 != null && texMap2On != 0)
                {
                    fresnelParameters.leftColor = new float[] { 1, 1, 1 };
                    texMap = texMap2;
                }
                else
                {
                    return(null);
                }
            }

            return(texMap);
        }
Exemplo n.º 3
0
        private BabylonTexture ExportEnvironmnentTexture(ITexmap texMap, BabylonScene babylonScene)
        {
            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                RaiseWarning("Failed to export environment texture. Uncheck \"Use Map\" option to fix this warning.");
                return(null);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

            if (texture == null)
            {
                RaiseWarning("Failed to export environment texture. Uncheck \"Use Map\" option to fix this warning.");
                return(null);
            }

            var sourcePath = texture.Map.FullFilePath;
            var fileName   = Path.GetFileName(sourcePath);

            // Allow only dds file format
            if (!fileName.EndsWith(".dds"))
            {
                RaiseWarning("Failed to export environment texture: only .dds format is supported. Uncheck \"Use map\" to fix this warning.");
                return(null);
            }

            var babylonTexture = new BabylonTexture
            {
                name = fileName
            };

            // Copy texture to output
            if (isBabylonExported)
            {
                var destPath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);

                if (CopyTexturesToOutput)
                {
                    try
                    {
                        if (File.Exists(sourcePath))
                        {
                            File.Copy(sourcePath, destPath, true);
                        }
                    }
                    catch
                    {
                        // silently fails
                    }
                }
            }

            return(babylonTexture);
        }
        private Bitmap _loadTexture(ITexmap texMap)
        {
            IBitmapTex texture = _getBitmapTex(texMap);

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

            return(TextureUtilities.LoadTexture(texture.Map.FullFilePath, this));
        }
Exemplo n.º 5
0
        private Bitmap _loadTexture(ITexmap texMap)
        {
            IBitmapTex texture = _getBitmapTex(texMap);

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

            return(LoadTexture(texture.Map.FullFilePath));
        }
        private string getSourcePath(ITexmap texMap)
        {
            IBitmapTex bitmapTex = _getBitmapTex(texMap);

            if (bitmapTex != null)
            {
                return(bitmapTex.Map.FullFilePath);
            }
            else
            {
                return(null);
            }
        }
Exemplo n.º 7
0
        private Bitmap _loadTexture(ITexmap texMap)
        {
            if (texMap == null || texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                return(null);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

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

            return(LoadTexture(texture.Map.FullFilePath));
        }
        // -------------------------
        // --------- Utils ---------
        // -------------------------

        private IBitmapTex _getBitmapTex(ITexmap texMap, bool raiseError = true)
        {
            if (texMap == null || texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                return(null);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

            if (texture == null && raiseError)
            {
                RaiseError($"Texture type is not supported. Use a Bitmap instead.", 2);
            }

            return(texture);
        }
        private bool isTextureOk(ITexmap texMap)
        {
            var texture = _getBitmapTex(texMap);

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

            if (!File.Exists(texture.Map.FullFilePath))
            {
                return(false);
            }

            return(true);
        }
        private ITexmap _getTexMap(IIGameMaterial materialNode, int index)
        {
            ITexmap texMap = null;

            if (materialNode.MaxMaterial.SubTexmapOn(index) == 1)
            {
                texMap = materialNode.MaxMaterial.GetSubTexmap(index);

                // No warning displayed because by default, physical material in 3ds Max have all maps on
                // Would be tedious for the user to uncheck all unused maps

                //if (texMap == null)
                //{
                //    RaiseWarning("Texture channel " + index + " activated but no texture found.", 2);
                //}
            }
            return(texMap);
        }
Exemplo n.º 11
0
        private BabylonTexture ExportEnvironmnentTexture(ITexmap texMap, BabylonScene babylonScene)
        {
            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                return(null);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

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

            var sourcePath = texture.Map.FullFilePath;

            var babylonTexture = new BabylonTexture
            {
                name = Path.GetFileName(sourcePath)
            };

            // Copy texture to output
            if (isBabylonExported)
            {
                var destPath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);

                if (CopyTexturesToOutput)
                {
                    try
                    {
                        if (File.Exists(sourcePath))
                        {
                            File.Copy(sourcePath, destPath, true);
                        }
                    }
                    catch
                    {
                        // silently fails
                    }
                }
            }

            return(babylonTexture);
        }
Exemplo n.º 12
0
        private BabylonFurMaterial ExportFurModifier(IModifier modifier, String sourceMeshName, BabylonScene babylonScene)
        {
            RaiseMessage("Export Fur Modifier", 2);
            var paramBlock = modifier.GetParamBlock(0);

            // 3dsMax "Cut Length" is in percentages - "100%" will be "20" babylon spacing
            // (babylon Fur length means the distance from the obj, while the length of the hair is the spacing)
            var cutLength = paramBlock.GetFloat(CUT_LENGTH_PARAM_ID, 0, 0);
            var spacing   = (int)Math.Round(cutLength / 5);

            // 3dsMax "Root Thick" is in percentages - "100%" will be "1" babylon density
            // (lower density in babylon is thicker hair - lower root thick in 3dsMax is thinner)
            var rootThickness = paramBlock.GetFloat(ROOT_THICKNESS_PARAM_ID, 0, 0);
            var density       = (int)Math.Ceiling((100.1f - rootThickness) / 5);

            var rootColor = paramBlock.GetColor(ROOT_COLOR_PARAM_ID, 0, 0);
            var furColor  = new float[] { rootColor.R, rootColor.G, rootColor.B };

            if (paramBlock.GetTexmap(MAPS_PARAM_ID, 0, 11) != null)
            {
                RaiseWarning("Tip texture is not supported. Use root texture instead", 2);
            }

            BabylonTexture diffuseTexture  = null;
            ITexmap        rootColorTexmap = paramBlock.GetTexmap(MAPS_PARAM_ID, 0, 14);

            if (rootColorTexmap != null)
            {
                diffuseTexture       = ExportTexture(rootColorTexmap, 0f, babylonScene);
                diffuseTexture.level = 1;
            }

            return(new BabylonFurMaterial
            {
                id = modifier.GetGuid().ToString(),
                name = modifier.GetGuid().ToString(),
                sourceMeshName = sourceMeshName,
                furDensity = density,
                furSpacing = spacing,
                diffuseTexture = diffuseTexture,
                furColor = furColor,
            });
        }
Exemplo n.º 13
0
        private bool isTextureOk(ITexmap texMap)
        {
            if (texMap == null || texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                return(false);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

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

            if (!File.Exists(texture.Map.FullFilePath))
            {
                return(false);
            }

            return(true);
        }
        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);
            }
        }
        /// <summary>
        /// Export dedicated to PbrMetalRough Material
        /// </summary>
        /// <param name="materialNode">the material node interface</param>
        /// <param name="babylonScene">the scene to export the material</param>
        private void ExportPbrMetalRoughMaterial(IIGameMaterial materialNode, BabylonScene babylonScene)
        {
            // build material decorator
            PbrMetalRoughDecorator maxDecorator = new PbrMetalRoughDecorator(materialNode);
            // get the custom babylon attribute decorator
            BabylonCustomAttributeDecorator babylonDecorator = maxDecorator.BabylonCustomAttributes;

            // the target material
            var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial(maxDecorator.Id)
            {
                maxGameMaterial     = materialNode,
                name                = maxDecorator.Name,
                backFaceCulling     = babylonDecorator.BackFaceCulling,
                doubleSided         = !babylonDecorator.BackFaceCulling,
                separateCullingPass = babylonDecorator.SeparateCullingPass,
                isUnlit             = babylonDecorator.IsUnlit,
                _unlit              = babylonDecorator.IsUnlit,
                baseColor           = maxDecorator.BaseColor.ToArray()
            };

            // --- Global ---
            if (babylonMaterial.isUnlit)
            {
                // Ignore values
                babylonMaterial.metallic  = 0;
                babylonMaterial.roughness = 0.9f;
            }
            else
            {
                babylonMaterial.metallic  = maxDecorator.Metalness;
                babylonMaterial.roughness = maxDecorator.Roughness;
                babylonMaterial.emissive  = maxDecorator.EmitColor.ToArray();
            }

            // --- Textures ---
            float[] multiplyColor = null;
            if (exportParameters.exportTextures)
            {
                ITexmap baseColorTexMap = maxDecorator.BaseColorMap;
                ITexmap alphaTexMap     = maxDecorator.OpacityMap;
                bool    isOpacity       = true;
                babylonMaterial.baseTexture = ExportBaseColorAlphaTexture(baseColorTexMap, alphaTexMap, babylonMaterial.baseColor, babylonMaterial.alpha, babylonScene, out multiplyColor, isOpacity);

                if (multiplyColor != null)
                {
                    babylonMaterial.baseColor = multiplyColor;
                }

                if (!babylonMaterial.isUnlit)
                {
                    // Metallic, roughness, ambient occlusion
                    ITexmap metalnessTexMap        = maxDecorator.MetalnessMap;
                    ITexmap roughnessTexMap        = maxDecorator.RoughnessMap;
                    ITexmap ambientOcclusionTexMap = maxDecorator.AmbientOcclusionMap;

                    // Check if MR or ORM textures are already merged
                    bool areTexturesAlreadyMerged = false;
                    if (metalnessTexMap != null && roughnessTexMap != null)
                    {
                        string sourcePathMetallic  = getSourcePath(metalnessTexMap);
                        string sourcePathRoughness = getSourcePath(roughnessTexMap);

                        if (sourcePathMetallic == sourcePathRoughness)
                        {
                            if (ambientOcclusionTexMap != null && exportParameters.mergeAO)
                            {
                                string sourcePathAmbientOcclusion = getSourcePath(ambientOcclusionTexMap);
                                if (sourcePathMetallic == sourcePathAmbientOcclusion)
                                {
                                    // Metallic, roughness and ambient occlusion are already merged
                                    RaiseVerbose("Metallic, roughness and ambient occlusion are already merged", 2);
                                    BabylonTexture ormTexture = ExportTexture(metalnessTexMap, babylonScene);
                                    babylonMaterial.metallicRoughnessTexture = ormTexture;
                                    babylonMaterial.occlusionTexture         = ormTexture;
                                    areTexturesAlreadyMerged = true;
                                }
                            }
                            else
                            {
                                // Metallic and roughness are already merged
                                RaiseVerbose("Metallic and roughness are already merged", 2);
                                BabylonTexture ormTexture = ExportTexture(metalnessTexMap, babylonScene);
                                babylonMaterial.metallicRoughnessTexture = ormTexture;
                                areTexturesAlreadyMerged = true;
                            }
                        }
                    }
                    if (areTexturesAlreadyMerged == false)
                    {
                        if (metalnessTexMap != null || roughnessTexMap != null)
                        {
                            // Merge metallic, roughness and ambient occlusion
                            RaiseVerbose("Merge metallic and roughness (and ambient occlusion if `mergeAOwithMR` is enabled)", 2);
                            BabylonTexture ormTexture = ExportORMTexture(exportParameters.mergeAO ? ambientOcclusionTexMap : null, roughnessTexMap, metalnessTexMap, babylonMaterial.metallic, babylonMaterial.roughness, babylonScene, false);
                            babylonMaterial.metallicRoughnessTexture = ormTexture;

                            if (ambientOcclusionTexMap != null)
                            {
                                if (exportParameters.mergeAO)
                                {
                                    // if the ambient occlusion texture map uses a different set of texture coordinates than
                                    // metallic roughness, create a new instance of the ORM BabylonTexture with the different texture
                                    // coordinate indices
                                    var ambientOcclusionTexture = _getBitmapTex(ambientOcclusionTexMap);
                                    var texCoordIndex           = ambientOcclusionTexture.UVGen.MapChannel - 1;
                                    if (texCoordIndex != ormTexture.coordinatesIndex)
                                    {
                                        babylonMaterial.occlusionTexture = new BabylonTexture(ormTexture);
                                        babylonMaterial.occlusionTexture.coordinatesIndex = texCoordIndex;
                                        // Set UVs/texture transform for the ambient occlusion texture
                                        var uvGen = _exportUV(ambientOcclusionTexture.UVGen, babylonMaterial.occlusionTexture);
                                    }
                                    else
                                    {
                                        babylonMaterial.occlusionTexture = ormTexture;
                                    }
                                }
                                else
                                {
                                    babylonMaterial.occlusionTexture = ExportTexture(ambientOcclusionTexMap, babylonScene);
                                }
                            }
                        }
                        else if (ambientOcclusionTexMap != null)
                        {
                            // Simply export occlusion texture
                            RaiseVerbose("Simply export occlusion texture", 2);
                            babylonMaterial.occlusionTexture = ExportTexture(ambientOcclusionTexMap, babylonScene);
                        }
                    }
                    if (ambientOcclusionTexMap != null && !exportParameters.mergeAO && babylonMaterial.occlusionTexture == null)
                    {
                        RaiseVerbose("Exporting occlusion texture without merging with metallic roughness", 2);
                        babylonMaterial.occlusionTexture = ExportTexture(ambientOcclusionTexMap, babylonScene);
                    }

                    var     normalMapAmount = maxDecorator.BumpMapAmount;
                    ITexmap normalTexMap    = maxDecorator.NormalMap;
                    babylonMaterial.normalTexture = ExportTexture(normalTexMap, babylonScene, normalMapAmount);

                    ITexmap emitTexMap = maxDecorator.EmitColormMap;
                    babylonMaterial.emissiveTexture = ExportTexture(emitTexMap, babylonScene);

                    if (babylonMaterial.metallicRoughnessTexture != null && !babylonDecorator.UseMaxFactor)
                    {
                        // Change the factor to zero if combining partial channel to avoid issue (in case of image compression).
                        // ie - if no metallic map, then b MUST be fully black. However channel of jpeg MAY not beeing fully black
                        // cause of the compression algorithm. Keeping MetallicFactor to 1 will make visible artifact onto texture. So set to Zero instead.
                        babylonMaterial.metallic  = areTexturesAlreadyMerged || metalnessTexMap != null ? 1.0f : 0.0f;
                        babylonMaterial.roughness = areTexturesAlreadyMerged || roughnessTexMap != null ? 1.0f : 0.0f;
                    }
                }
            }

            if (babylonMaterial.alpha != 1.0f || (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha))
            {
                babylonMaterial.transparencyMode = (int)BabylonMaterial.TransparencyMode.ALPHABLEND;
            }

            if (babylonMaterial.transparencyMode == (int)BabylonMaterial.TransparencyMode.ALPHATEST)
            {
                // Set the alphaCutOff value explicitely to avoid different interpretations on different engines
                // Use the glTF default value rather than the babylon one
                babylonMaterial.alphaCutOff = 0.5f;
            }


            if (babylonMaterial.emissiveTexture != null)
            {
                babylonMaterial.emissive = new[] { 1.0f, 1.0f, 1.0f };
            }

            // Add babylon attributes
            if (babylonDecorator.Properties == null)
            {
                AddPhysicalBabylonAttributes(materialNode.MaterialName, babylonMaterial);
            }


            // List all babylon material attributes
            // Those attributes are currently stored into the native material
            // They should not be exported as extra attributes
            var doNotExport = BabylonCustomAttributeDecorator.ListPrivatePropertyNames().ToList();

            // Export the custom attributes of this material
            babylonMaterial.metadata = ExportExtraAttributes(materialNode, babylonScene, doNotExport);

            if (exportParameters.pbrFull)
            {
                var fullPBR = new BabylonPBRMaterial(babylonMaterial)
                {
                    directIntensity      = babylonDecorator.DirectIntensity,
                    emissiveIntensity    = babylonDecorator.EmissiveIntensity,
                    environmentIntensity = babylonDecorator.EnvironementIntensity,
                    specularIntensity    = babylonDecorator.SpecularIntensity,
                    maxGameMaterial      = babylonMaterial.maxGameMaterial
                };
                babylonScene.MaterialsList.Add(fullPBR);
            }
            else
            {
                // Add the material to the scene
                babylonScene.MaterialsList.Add(babylonMaterial);
            }
        }
        /// <summary>
        /// Export dedicated to SpecGloss Material
        /// </summary>
        /// <param name="materialNode">the material node interface</param>
        /// <param name="babylonScene">the scene to export the material</param>
        private void ExportPbrSpecGlossMaterial(IIGameMaterial materialNode, BabylonScene babylonScene)
        {
            // build material decorator
            PbrSpecGlossDecorator maxDecorator = new PbrSpecGlossDecorator(materialNode);
            // get the custom babylon attribute decorator
            BabylonCustomAttributeDecorator babylonDecorator = maxDecorator.BabylonCustomAttributes;

            // the target material
            var babylonMaterial = new BabylonPBRSpecularGlossinessMaterial(maxDecorator.Id)
            {
                maxGameMaterial     = materialNode,
                name                = maxDecorator.Name,
                backFaceCulling     = babylonDecorator.BackFaceCulling,
                doubleSided         = !babylonDecorator.BackFaceCulling,
                separateCullingPass = babylonDecorator.SeparateCullingPass,
                isUnlit             = babylonDecorator.IsUnlit,
                baseColor           = maxDecorator.BaseColor.ToArray(),
            };

            // --- Global ---
            if (babylonMaterial.isUnlit)
            {
                // Ignore values
                babylonMaterial.specularColor = BabylonPBRBaseSimpleMaterial.BlackColor();
                babylonMaterial.glossiness    = 0;
            }
            else
            {
                babylonMaterial.glossiness    = maxDecorator.Glossiness;
                babylonMaterial.specularColor = maxDecorator.SpecularColor.ToArray();
                babylonMaterial.emissive      = maxDecorator.EmitColor.ToArray();
            }

            // --- Textures ---
            float[] multiplyColor = null;
            if (exportParameters.exportTextures)
            {
                ITexmap diffuseTexMap = maxDecorator.BaseColorMap;
                ITexmap alphaTexMap   = maxDecorator.OpacityMap;
                bool    isOpacity     = true;
                babylonMaterial.diffuseTexture = ExportBaseColorAlphaTexture(diffuseTexMap, alphaTexMap, babylonMaterial.baseColor, babylonMaterial.alpha, babylonScene, out multiplyColor, isOpacity);
                if (multiplyColor != null)
                {
                    babylonMaterial.baseColor = multiplyColor;
                }

                if (!babylonMaterial.isUnlit)
                {
                    // Metallic, roughness, ambient occlusion
                    ITexmap specularTexMap         = maxDecorator.SpecularMap;
                    ITexmap glossinessTexMap       = maxDecorator.GlossinessMap;
                    ITexmap ambientOcclusionTexMap = maxDecorator.AmbientOcclusionMap;

                    if (specularTexMap != null || glossinessTexMap != null)
                    {
                        // Merge Specular and Glossiness
                        RaiseVerbose("Merge Specular and Glossiness", 2);
                        BabylonTexture specularGlossinessTexture = ExportSpecularGlossinessTexture(babylonMaterial.specularColor, specularTexMap, babylonMaterial.glossiness, glossinessTexMap, babylonScene);
                        babylonMaterial.specularGlossinessTexture = specularGlossinessTexture;
                    }

                    if (ambientOcclusionTexMap != null)
                    {
                        // Simply export occlusion texture
                        RaiseVerbose("Export occlusion texture", 2);
                        babylonMaterial.occlusionTexture = ExportTexture(ambientOcclusionTexMap, babylonScene);
                    }

                    var     normalMapAmount = maxDecorator.BumpMapAmount;
                    ITexmap normalTexMap    = maxDecorator.NormalMap;
                    babylonMaterial.normalTexture = ExportTexture(normalTexMap, babylonScene, normalMapAmount);

                    ITexmap emitTexMap = maxDecorator.EmitColormMap;
                    babylonMaterial.emissiveTexture = ExportTexture(emitTexMap, babylonScene);

                    if (babylonMaterial.specularGlossinessTexture != null && !babylonDecorator.UseMaxFactor)
                    {
                        babylonMaterial.glossiness    = glossinessTexMap != null ? 1.0f : 0.0f;
                        babylonMaterial.specularColor = specularTexMap != null?BabylonPBRBaseSimpleMaterial.WhiteColor() : BabylonPBRBaseSimpleMaterial.BlackColor();
                    }
                }
            }


            // --- Finalize ---
            if (babylonMaterial.alpha != 1.0f || (babylonMaterial.diffuseTexture != null && babylonMaterial.diffuseTexture.hasAlpha))
            {
                babylonMaterial.transparencyMode = (int)BabylonMaterial.TransparencyMode.ALPHABLEND;
            }

            if (babylonMaterial.transparencyMode == (int)BabylonMaterial.TransparencyMode.ALPHATEST)
            {
                // Set the alphaCutOff value explicitely to avoid different interpretations on different engines
                // Use the glTF default value rather than the babylon one
                babylonMaterial.alphaCutOff = 0.5f;
            }

            if (babylonMaterial.emissiveTexture != null)
            {
                babylonMaterial.emissive = new[] { 1.0f, 1.0f, 1.0f };
            }


            // List all babylon material attributes
            // Those attributes are currently stored into the native material
            // They should not be exported as extra attributes
            var doNotExport = BabylonCustomAttributeDecorator.ListPrivatePropertyNames().ToList();

            // Export the custom attributes of this material
            babylonMaterial.metadata = ExportExtraAttributes(materialNode, babylonScene, doNotExport);

            if (exportParameters.pbrFull)
            {
                var fullPBR = new BabylonPBRMaterial(babylonMaterial)
                {
                    directIntensity      = babylonDecorator.DirectIntensity,
                    emissiveIntensity    = babylonDecorator.EmissiveIntensity,
                    environmentIntensity = babylonDecorator.EnvironementIntensity,
                    specularIntensity    = babylonDecorator.SpecularIntensity,
                    maxGameMaterial      = babylonMaterial.maxGameMaterial
                };
                babylonScene.MaterialsList.Add(fullPBR);
            }
            else
            {
                // Add the material to the scene
                babylonScene.MaterialsList.Add(babylonMaterial);
            }
        }
Exemplo n.º 19
0
        private BabylonTexture ExportMetallicRoughnessTexture(IIGameMaterial materialNode, float metallic, float roughness, BabylonScene babylonScene, string materialName, bool invertRoughness)
        {
            ITexmap metallicTexMap  = _getTexMap(materialNode, 5);
            ITexmap roughnessTexMap = _getTexMap(materialNode, 4);

            // --- Babylon texture ---

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

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

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

            var babylonTexture = new BabylonTexture
            {
                name = materialName + "_metallicRoughness" + ".jpg" // TODO - unsafe name, may conflict with another texture name
            };

            // Level
            babylonTexture.level = 1.0f;

            // No alpha
            babylonTexture.hasAlpha        = false;
            babylonTexture.getAlphaFromRGB = false;

            // 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 (CopyTexturesToOutput)
            {
                // Load bitmaps
                var metallicBitmap  = _loadTexture(metallicTexMap);
                var roughnessBitmap = _loadTexture(roughnessTexMap);

                // Retreive dimensions
                int width              = 0;
                int height             = 0;
                var haveSameDimensions = _getMinimalBitmapDimensions(out width, out height, metallicBitmap, roughnessBitmap);
                if (!haveSameDimensions)
                {
                    RaiseError("Metallic and roughness maps should have same dimensions", 2);
                }

                // Create metallic+roughness map
                Bitmap metallicRoughnessBitmap = new Bitmap(width, height);
                for (int x = 0; x < width; x++)
                {
                    for (int y = 0; y < height; y++)
                    {
                        var _metallic = metallicBitmap != null?metallicBitmap.GetPixel(x, y).B:
                                        metallic * 255.0f;

                        var _roughness = roughnessBitmap != null ? (invertRoughness ? 255 - roughnessBitmap.GetPixel(x, y).G : roughnessBitmap.GetPixel(x, y).G) :
                                         roughness * 255.0f;

                        // 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)_roughness,
                            (int)_metallic
                            );
                        metallicRoughnessBitmap.SetPixel(x, y, colorMetallicRoughness);
                    }
                }

                // Write bitmap
                if (isBabylonExported)
                {
                    var absolutePath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);
                    RaiseMessage($"Texture | write image '{babylonTexture.name}'", 2);
                    metallicRoughnessBitmap.Save(absolutePath, System.Drawing.Imaging.ImageFormat.Jpeg);
                }
                else
                {
                    // Store created bitmap for further use in gltf export
                    babylonTexture.bitmap = metallicRoughnessBitmap;
                }
            }

            return(babylonTexture);
        }
        private BabylonTexture ExportTexture(ITexmap texMap, BabylonScene babylonScene, float amount = 1.0f, bool allowCube = false, bool forceAlpha = false)
        {
            IBitmapTex texture = _getBitmapTex(texMap, false);

            if (texture == null)
            {
                float specialAmount;
                var   specialTexMap = _getSpecialTexmap(texMap, out specialAmount);
                texture = _getBitmapTex(specialTexMap, false);
                amount *= specialAmount;
            }

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

            var sourcePath = texture.Map.FullFilePath;

            if (sourcePath == null || sourcePath == "")
            {
                RaiseWarning("Texture path is missing.", 2);
                return(null);
            }

            RaiseMessage("Export texture named: " + Path.GetFileName(sourcePath), 2);

            var validImageFormat = TextureUtilities.GetValidImageFormat(Path.GetExtension(sourcePath));

            if (validImageFormat == null)
            {
                // Image format is not supported by the exporter
                RaiseWarning(string.Format("Format of texture {0} is not supported by the exporter. Consider using a standard image format like jpg or png.", Path.GetFileName(sourcePath)), 3);
                return(null);
            }
            var textureID = texture.GetGuid().ToString();

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }
            else
            {
                var babylonTexture = new BabylonTexture(textureID)
                {
                    name = Path.GetFileNameWithoutExtension(texture.MapName) + "." + validImageFormat
                };
                RaiseMessage($"texture id = {babylonTexture.Id}", 2);

                // Level
                babylonTexture.level = amount;

                // Alpha
                if (forceAlpha)
                {
                    babylonTexture.hasAlpha        = true;
                    babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3); // 'RGB intensity' or 'None (Opaque)'
                }
                else
                {
                    babylonTexture.hasAlpha        = (texture.AlphaSource != 3); // Not 'None (Opaque)'
                    babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2); // 'RGB intensity'
                }

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

                // Animations
                var animations = new List <BabylonAnimation>();
                ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) });
                ExportFloatAnimation("vOffset", animations, key => new[] { -uvGen.GetVOffs(key) });
                ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) });
                ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) });
                ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) });
                ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) });
                ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
                babylonTexture.animations = animations.ToArray();

                // Copy texture to output
                if (isBabylonExported)
                {
                    var destPath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);
                    TextureUtilities.CopyTexture(sourcePath, destPath, exportParameters.txtQuality, this);

                    // Is cube
                    _exportIsCube(Path.Combine(babylonScene.OutputPath, babylonTexture.name), babylonTexture, allowCube);
                }
                else
                {
                    babylonTexture.isCube = false;
                }
                babylonTexture.originalPath = sourcePath;

                return(babylonTexture);
            }
        }
        private BabylonTexture ExportMetallicRoughnessTexture(IIGameMaterial materialNode, float metallic, float roughness, BabylonScene babylonScene, string materialName)
        {
            ITexmap metallicTexMap  = _getTexMap(materialNode, 5);
            ITexmap roughnessTexMap = _getTexMap(materialNode, 4);

            if (metallicTexMap == null && roughnessTexMap == null)
            {
                return(null);
            }

            // Use one as a reference for UVs parameters
            var referenceTexMap = metallicTexMap != null ? metallicTexMap : roughnessTexMap;


            // --- Babylon texture ---

            if (referenceTexMap.GetParamBlock(0) == null || referenceTexMap.GetParamBlock(0).Owner == null)
            {
                return(null);
            }

            var texture = referenceTexMap.GetParamBlock(0).Owner as IBitmapTex;

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

            var babylonTexture = new BabylonTexture
            {
                name = materialName + "_metallicRoughness" + ".jpg" // TODO - unsafe name, may conflict with another texture name
            };

            // Level
            babylonTexture.level = 1.0f;

            // No alpha
            babylonTexture.hasAlpha        = false;
            babylonTexture.getAlphaFromRGB = false;

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

            // Is cube
            _exportIsCube(texture, babylonTexture, false);


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

            // Load bitmaps
            var metallicBitmap  = _loadTexture(metallicTexMap);
            var roughnessBitmap = _loadTexture(roughnessTexMap);

            // Retreive dimensions
            int width              = 0;
            int height             = 0;
            var haveSameDimensions = _getMinimalBitmapDimensions(out width, out height, metallicBitmap, roughnessBitmap);

            if (!haveSameDimensions)
            {
                RaiseWarning("Metallic and roughness maps should have same dimensions", 2);
            }

            // Create metallic+roughness map
            Bitmap metallicRoughnessBitmap = new Bitmap(width, height);

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    var _metallic = metallicBitmap != null?metallicBitmap.GetPixel(x, y).R:
                                    metallic * 255.0f;

                    var _roughness = roughnessBitmap != null?roughnessBitmap.GetPixel(x, y).R:
                                     roughness * 255.0f;

                    // 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)_roughness,
                        (int)_metallic
                        );
                    metallicRoughnessBitmap.SetPixel(x, y, colorMetallicRoughness);
                }
            }

            // Write bitmap
            var absolutePath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);

            RaiseMessage($"Texture | write image '{babylonTexture.name}'", 2);
            metallicRoughnessBitmap.Save(absolutePath);

            return(babylonTexture);
        }
        // -------------------------
        // -- Export sub methods ---
        // -------------------------

        private BabylonTexture _exportTexture(ITexmap texMap, float amount, BabylonScene babylonScene, bool allowCube = false, bool forceAlpha = false)
        {
            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                return(null);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

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

            var babylonTexture = new BabylonTexture
            {
                name = Path.GetFileName(texture.MapName)
            };

            // Level
            babylonTexture.level = amount;

            // Alpha
            if (forceAlpha)
            {
                babylonTexture.hasAlpha        = true;
                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3); // 'RGB intensity' or 'None (Opaque)'
            }
            else
            {
                babylonTexture.hasAlpha        = (texture.AlphaSource != 3); // Not 'None (Opaque)'
                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2); // 'RGB intensity'
            }

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

            // Animations
            var animations = new List <BabylonAnimation>();

            ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) });
            ExportFloatAnimation("vOffset", animations, key => new[] { -uvGen.GetVOffs(key) });
            ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) });
            ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) });
            ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) });
            ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) });
            ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
            babylonTexture.animations = animations.ToArray();

            // Is cube
            _exportIsCube(texture, babylonTexture, allowCube);

            // Copy texture to output
            var absolutePath = texture.Map.FullFilePath;

            try
            {
                if (File.Exists(absolutePath))
                {
                    if (CopyTexturesToOutput)
                    {
                        File.Copy(absolutePath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true);
                    }
                }
            }
            catch
            {
                // silently fails
            }

            return(babylonTexture);
        }
        private BabylonTexture ExportBaseColorAlphaTexture(IIGameMaterial materialNode, BabylonScene babylonScene, string materialName)
        {
            ITexmap baseColorTexMap = _getTexMap(materialNode, 1);
            ITexmap alphaTexMap     = _getTexMap(materialNode, 9); // Transparency weight map

            // --- Babylon texture ---

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

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

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

            var hasAlpha = alphaTexMap != null || (baseColorTexture != null && baseColorTexture.AlphaSource == 0); // Alpha source is 'Image Alpha'

            var babylonTexture = new BabylonTexture
            {
                name = materialName + "_baseColor" + (hasAlpha ? ".png" : ".jpg") // TODO - unsafe name, may conflict with another texture name
            };

            // Level
            babylonTexture.level = 1.0f;

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

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

            // Is cube
            _exportIsCube(texture, babylonTexture, false);


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

            // Load bitmaps
            var baseColorBitmap = _loadTexture(baseColorTexMap);
            var alphaBitmap     = _loadTexture(alphaTexMap);

            // Retreive dimensions
            int width              = 0;
            int height             = 0;
            var haveSameDimensions = _getMinimalBitmapDimensions(out width, out height, baseColorBitmap, alphaBitmap);

            if (!haveSameDimensions)
            {
                RaiseWarning("Base color and transparency color maps should have same dimensions", 2);
            }

            var getAlphaFromRGB = false;

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

            // Create baseColor+alpha map
            Bitmap baseColorAlphaBitmap = new Bitmap(width, height);

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    var baseColor = baseColorBitmap != null?baseColorBitmap.GetPixel(x, y) : Color.FromArgb(255, 255, 255);

                    Color baseColorAlpha;
                    if (babylonTexture.hasAlpha)
                    {
                        if (alphaBitmap != null)
                        {
                            // Retreive alpha from alpha texture
                            var alphaColor = alphaBitmap.GetPixel(x, y);
                            var alpha      = getAlphaFromRGB ? alphaColor.R : alphaColor.A;
                            baseColorAlpha = Color.FromArgb(alpha, baseColor);
                        }
                        else
                        {
                            // Use all channels from base color
                            baseColorAlpha = baseColor;
                        }
                    }
                    else
                    {
                        // Only use RGB channels from base color
                        baseColorAlpha = Color.FromArgb(baseColor.R, baseColor.G, baseColor.B);
                    }
                    baseColorAlphaBitmap.SetPixel(x, y, baseColorAlpha);
                }
            }

            // Write bitmap
            var absolutePath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);

            RaiseMessage($"Texture | write image '{babylonTexture.name}'", 2);
            baseColorAlphaBitmap.Save(absolutePath);

            return(babylonTexture);
        }
Exemplo n.º 24
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);
        }
Exemplo n.º 25
0
        // -------------------------
        // -- Export sub methods ---
        // -------------------------

        private BabylonTexture ExportTexture(ITexmap texMap, float amount, BabylonScene babylonScene, bool allowCube = false, bool forceAlpha = false)
        {
            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                return(null);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

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

            var sourcePath = texture.Map.FullFilePath;

            if (sourcePath == null || sourcePath == "")
            {
                RaiseWarning("Texture path is missing.", 2);
                return(null);
            }

            var validImageFormat = GetValidImageFormat(Path.GetExtension(sourcePath));

            if (validImageFormat == null)
            {
                // Image format is not supported by the exporter
                RaiseWarning(string.Format("Format of texture {0} is not supported by the exporter. Consider using a standard image format like jpg or png.", Path.GetFileName(sourcePath)), 2);
                return(null);
            }

            var babylonTexture = new BabylonTexture
            {
                name = Path.GetFileNameWithoutExtension(texture.MapName) + "." + validImageFormat
            };

            // Level
            babylonTexture.level = amount;

            // Alpha
            if (forceAlpha)
            {
                babylonTexture.hasAlpha        = true;
                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3); // 'RGB intensity' or 'None (Opaque)'
            }
            else
            {
                babylonTexture.hasAlpha        = (texture.AlphaSource != 3); // Not 'None (Opaque)'
                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2); // 'RGB intensity'
            }

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

            // Animations
            var animations = new List <BabylonAnimation>();

            ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) });
            ExportFloatAnimation("vOffset", animations, key => new[] { -uvGen.GetVOffs(key) });
            ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) });
            ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) });
            ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) });
            ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) });
            ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
            babylonTexture.animations = animations.ToArray();

            // Copy texture to output
            if (isBabylonExported)
            {
                var destPath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);
                CopyTexture(sourcePath, destPath);

                // Is cube
                _exportIsCube(Path.Combine(babylonScene.OutputPath, babylonTexture.name), babylonTexture, allowCube);
            }
            else
            {
                babylonTexture.originalPath = sourcePath;
                babylonTexture.isCube       = false;
            }

            return(babylonTexture);
        }
Exemplo n.º 26
0
        /// <summary>
        /// Return custom attributes retreive from a max object named "obj"
        /// </summary>
        /// <param name="metadata"></param>
        /// <param name="propertyContainer"></param>
        /// <param name="babylonScene"></param>
        /// <param name="excludeAttributes">Attribute names to not export</param>
        private Dictionary <string, object> _ExportExtraAttributes(IIPropertyContainer propertyContainer, BabylonScene babylonScene, List <string> excludeAttributes = null)
        {
            logger?.RaiseMessage("ExportExtraAttributes", 2);

            // Return a string encoded with 2 separators
            // Parameter separator: _$€PParam_
            // Name/Type separator: _$€PType_
            string cmd = "s = \"\""
                         + "\r\n" + "for objDef in (custAttributes.getDefs obj) do"
                         + "\r\n" + "("
                         + "\r\n" + "pbArray = custAttributes.getPBlockDefs objdef"
                         + "\r\n" + "for indexPBlock = 1 to pbArray.count do"
                         + "\r\n" + "("
                         + "\r\n" + "itms = pbArray[indexPBlock]"
                         + "\r\n" + "for y = 5 to itms.Count do"
                         + "\r\n" + "("
                         + "\r\n" + "s = s + \"_$€PParam_\" + itms[y][1]"
                         + "\r\n" + "for z = 1 to itms[y][2].Count by 2 do"
                         + "\r\n" + "("
                         + "\r\n" + "key = itms[y][2][z] as string"
                         + "\r\n" + "if (findString key \"type\") != undefined then"
                         + "\r\n" + "("
                         + "\r\n" + "s = s + \"_$€PType_\" + itms[y][2][z+1]"
                         + "\r\n" + ")"
                         + "\r\n" + ")"
                         + "\r\n" + ")"
                         + "\r\n" + ")"
                         + "\r\n" + ")"
                         + "\r\n" + "s";
            string result = ScriptsUtilities.ExecuteMaxScriptQuery(cmd);

            if (result == null || result == "")
            {
                return(null);
            }

            // Parse the result into a dictionary
            string[] parameters = result.Split(new string[] { "_$€PParam_" }, StringSplitOptions.RemoveEmptyEntries);
            Dictionary <string, string> customAttributesTypeByName = new Dictionary <string, string>();

            foreach (string parameter in parameters)
            {
                string[] customAttribute = parameter.Split(new string[] { "_$€PType_" }, StringSplitOptions.RemoveEmptyEntries);
                string   key             = customAttribute[0];
                if (customAttributesTypeByName.ContainsKey(key) == false)
                {
                    customAttributesTypeByName.Add(key, customAttribute[1]);
                }
            }

            // Remove preset custom attributes
            customAttributesTypeByName.Remove("presetName_str");
            customAttributesTypeByName.Remove("preset_str");
            customAttributesTypeByName.Remove("rampOn");

            // Remove specified attributes
            if (excludeAttributes != null)
            {
                foreach (string excludeAttribute in excludeAttributes)
                {
                    customAttributesTypeByName.Remove(excludeAttribute);
                }
            }

            // Handle each attribute type
            Dictionary <string, object> metadata = new Dictionary <string, object>();

            foreach (KeyValuePair <string, string> entry in customAttributesTypeByName)
            {
                object obj = null;

                logger?.RaiseMessage(entry.Key + "=" + entry.Value, 2);

                switch (entry.Value.ToLowerInvariant())
                {
                case "float":
                case "angle":     // in rad units
                case "worldunits":
                    obj = propertyContainer.GetFloatProperty(entry.Key);
                    break;

                case "percent":     // in base 1 (80% => 0.8)
                    obj = propertyContainer.GetFloatProperty(entry.Key) / 100f;
                    break;

                case "boolean":
                    obj = propertyContainer.GetBoolProperty(entry.Key);
                    break;

                case "integer":
                case "array":     // selected enum value expressed as int starting from 1
                    obj = propertyContainer.GetIntProperty(entry.Key);
                    break;

                case "string":
                    obj = propertyContainer.GetStringProperty(entry.Key);
                    break;

                case "color":     // Color RGB in base 1 (not 255)
                    obj = propertyContainer.GetPoint3Property(entry.Key).ToArray();
                    break;

                case "frgba":     // Color RGBA in base 1 (not 255)
                    obj = propertyContainer.GetPoint4Property(entry.Key).ToArray();
                    break;

                case "texturemap":
                    IIGameProperty gameProperty = propertyContainer.QueryProperty(entry.Key);
                    ITexmap        texmap       = gameProperty.MaxParamBlock2.GetTexmap(gameProperty.ParamID, 0, 0);
                    obj = ExportTexture(texmap, babylonScene);
                    break;

                case "node":
                    // Currently not exported
                    break;

                case "material":
                    // Currently not exported
                    break;

                default:
                    logger?.RaiseWarning("Unknown type '" + entry.Value + "' for custom attribute named '" + entry.Key + "'", 2);
                    break;
                }

                if (obj != null)
                {
                    metadata.Add(entry.Key, obj);
                }
            }

            // Print all extra attributes
            foreach (KeyValuePair <string, object> entry in metadata)
            {
                logger?.RaiseVerbose(entry.Key + "=" + entry.Value, 2);
            }

            return(metadata);
        }
        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);
            }
        }
Exemplo n.º 28
0
 internal Texture(ITexmap x) : base(x) { }
        // -------------------------
        // -- Export sub methods ---
        // -------------------------

        private ITexmap _getSpecialTexmap(ITexmap texMap, out float amount)
        {
            if (texMap == null)
            {
                amount = 0.0f;
                return(null);
            }

            if (texMap.ClassName == "Normal Bump")
            {
                var block = texMap.GetParamBlockByID(0);        // General Block
                if (block != null)
                {
                    amount = block.GetFloat(0, 0, 0);           // Normal texture Mult Spin
                    var map        = block.GetTexmap(2, 0, 0);  // Normal texture
                    var mapEnabled = block.GetInt(4, 0, 0);     // Normal texture Enable
                    if (mapEnabled == 0)
                    {
                        RaiseError($"Only Normal Bump Texture with Normal enabled are supported.", 2);
                        return(null);
                    }

                    var method = block.GetInt(6, 0, 0);         // Normal texture mode (Tangent, screen...)
                    if (method != 0)
                    {
                        RaiseError($"Only Normal Bump Texture in tangent space are supported.", 2);
                        return(null);
                    }
                    var flipR = block.GetInt(7, 0, 0);          // Normal texture Red chanel Flip
                    if (flipR != 0)
                    {
                        RaiseError($"Only Normal Bump Texture without R flip are supported.", 2);
                        return(null);
                    }
                    var flipG = block.GetInt(8, 0, 0);          // Normal texture Green chanel Flip
                    if (flipG != 0)
                    {
                        RaiseError($"Only Normal Bump Texture without G flip are supported.", 2);
                        return(null);
                    }
                    var swapRG = block.GetInt(9, 0, 0);         // Normal texture swap R and G channels
                    if (swapRG != 0)
                    {
                        RaiseError($"Only Normal Bump Texture without R and G swap are supported.", 2);
                        return(null);
                    }

                    // var bumpAmount = block.GetFloat(1, 0, 0);   // Bump texture Mult Spin
                    // var bumpMap = block.GetMap(3, 0, 0);        // Bump texture
                    var bumpMapEnable = block.GetInt(5, 0, 0);  // Bump texture Enable
                    if (bumpMapEnable == 1)
                    {
                        RaiseError($"Only Normal Bump Texture without Bump are supported.", 2);
                        return(null);
                    }

                    return(map);
                }
            }

            amount = 0.0f;
            RaiseError($"Texture type is not supported. Use a Bitmap or Normal Bump map instead.", 2);
            return(null);
        }
Exemplo n.º 30
0
 public TextureMapWrapper(ITexmap textureMap)
 {
    this.TextureMap = textureMap;
 }
Exemplo n.º 31
0
        private BabylonTexture ExportBaseColorAlphaTexture(IIGameMaterial materialNode, float[] baseColor, float alpha, BabylonScene babylonScene, string materialName)
        {
            ITexmap baseColorTexMap = _getTexMap(materialNode, 1);
            ITexmap alphaTexMap     = _getTexMap(materialNode, 9); // Transparency weight map

            // --- Babylon texture ---

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

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

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

            var babylonTexture = new BabylonTexture
            {
                name = materialName + "_baseColor.png" // 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
            babylonTexture.hasAlpha        = isTextureOk(alphaTexMap) || (isTextureOk(baseColorTexMap) && baseColorTexture.AlphaSource == 0);
            babylonTexture.getAlphaFromRGB = false;

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

            if (CopyTexturesToOutput)
            {
                // Load bitmaps
                var baseColorBitmap = _loadTexture(baseColorTexMap);
                var alphaBitmap     = _loadTexture(alphaTexMap);

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

                var getAlphaFromRGB = false;
                if (alphaTexture != null)
                {
                    getAlphaFromRGB = (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
                            var alphaColor   = alphaBitmap.GetPixel(x, y);
                            var alphaAtPixel = 255 - (getAlphaFromRGB ? alphaColor.R : alphaColor.A);
                            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)
                {
                    var absolutePath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);
                    RaiseMessage($"Texture | write image '{babylonTexture.name}'", 2);
                    baseColorAlphaBitmap.Save(absolutePath, System.Drawing.Imaging.ImageFormat.Png); // Explicit image format even though png is default
                }
                else
                {
                    // Store created bitmap for further use in gltf export
                    babylonTexture.bitmap = baseColorAlphaBitmap;
                }
            }

            return(babylonTexture);
        }
Exemplo n.º 32
0
        private void ExportMaterial(IIGameMaterial materialNode, BabylonScene babylonScene)
        {
            var name = materialNode.MaterialName;
            var id   = materialNode.MaxMaterial.GetGuid().ToString();

            // Check if the material was already exported. The material id is unique.
            if (babylonScene.MaterialsList.FirstOrDefault(m => m.id == id) != null)
            {
                return;
            }

            RaiseMessage(name, 1);

            // --- prints ---
            #region prints
            {
                RaiseVerbose("materialNode.MaterialClass=" + materialNode.MaterialClass, 2);
                RaiseVerbose("materialNode.NumberOfTextureMaps=" + materialNode.NumberOfTextureMaps, 2);

                var propertyContainer = materialNode.IPropertyContainer;
                RaiseVerbose("propertyContainer=" + propertyContainer, 2);
                if (propertyContainer != null)
                {
                    RaiseVerbose("propertyContainer.NumberOfProperties=" + propertyContainer.NumberOfProperties, 3);
                    for (int i = 0; i < propertyContainer.NumberOfProperties; i++)
                    {
                        var prop = propertyContainer.GetProperty(i);
                        if (prop != null)
                        {
                            RaiseVerbose("propertyContainer.GetProperty(" + i + ")=" + prop.Name, 3);
                            switch (prop.GetType_)
                            {
                            case PropType.StringProp:
                                string propertyString = "";
                                RaiseVerbose("prop.GetPropertyValue(ref propertyString, 0)=" + prop.GetPropertyValue(ref propertyString, 0), 4);
                                RaiseVerbose("propertyString=" + propertyString, 4);
                                break;

                            case PropType.IntProp:
                                int propertyInt = 0;
                                RaiseVerbose("prop.GetPropertyValue(ref propertyInt, 0)=" + prop.GetPropertyValue(ref propertyInt, 0), 4);
                                RaiseVerbose("propertyInt=" + propertyInt, 4);
                                break;

                            case PropType.FloatProp:
                                float propertyFloat = 0;
                                RaiseVerbose("prop.GetPropertyValue(ref propertyFloat, 0, true)=" + prop.GetPropertyValue(ref propertyFloat, 0, true), 4);
                                RaiseVerbose("propertyFloat=" + propertyFloat, 4);
                                RaiseVerbose("prop.GetPropertyValue(ref propertyFloat, 0, false)=" + prop.GetPropertyValue(ref propertyFloat, 0, false), 4);
                                RaiseVerbose("propertyFloat=" + propertyFloat, 4);
                                break;

                            case PropType.Point3Prop:
                                IPoint3 propertyPoint3 = Loader.Global.Point3.Create(0, 0, 0);
                                RaiseVerbose("prop.GetPropertyValue(ref propertyPoint3, 0)=" + prop.GetPropertyValue(propertyPoint3, 0), 4);
                                RaiseVerbose("propertyPoint3=" + Point3ToString(propertyPoint3), 4);
                                break;

                            case PropType.Point4Prop:
                                IPoint4 propertyPoint4 = Loader.Global.Point4.Create(0, 0, 0, 0);
                                RaiseVerbose("prop.GetPropertyValue(ref propertyPoint4, 0)=" + prop.GetPropertyValue(propertyPoint4, 0), 4);
                                RaiseVerbose("propertyPoint4=" + Point4ToString(propertyPoint4), 4);
                                break;

                            case PropType.UnknownProp:
                            default:
                                RaiseVerbose("Unknown property type", 4);
                                break;
                            }
                        }
                        else
                        {
                            RaiseVerbose("propertyContainer.GetProperty(" + i + ") IS NULL", 3);
                        }
                    }
                }
            }
            #endregion

            if (materialNode.SubMaterialCount > 0)
            {
                var babylonMultimaterial = new BabylonMultiMaterial {
                    name = name, id = id
                };

                var guids = new List <string>();

                for (var index = 0; index < materialNode.SubMaterialCount; index++)
                {
                    var subMat = materialNode.GetSubMaterial(index);

                    if (subMat != null)
                    {
                        guids.Add(subMat.MaxMaterial.GetGuid().ToString());

                        if (!referencedMaterials.Contains(subMat))
                        {
                            referencedMaterials.Add(subMat);
                            ExportMaterial(subMat, babylonScene);
                        }
                    }
                    else
                    {
                        guids.Add(Guid.Empty.ToString());
                    }
                }

                babylonMultimaterial.materials = guids.ToArray();

                babylonScene.MultiMaterialsList.Add(babylonMultimaterial);
                return;
            }

            var  unlitProperty = materialNode.IPropertyContainer.QueryProperty("BabylonUnlit");
            bool isUnlit       = unlitProperty != null?unlitProperty.GetBoolValue() : false;


            var stdMat = materialNode.MaxMaterial.NumParamBlocks > 0 ? materialNode.MaxMaterial.GetParamBlock(0).Owner as IStdMat2 : null;

            if (stdMat != null)
            {
                var babylonMaterial = new BabylonStandardMaterial
                {
                    name    = name,
                    id      = id,
                    isUnlit = isUnlit,
                    diffuse = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray(),
                    alpha   = 1.0f - materialNode.MaxMaterial.GetXParency(0, false)
                };

                babylonMaterial.backFaceCulling = !stdMat.TwoSided;
                babylonMaterial.wireframe       = stdMat.Wire;

                var isSelfIllumColor = materialNode.MaxMaterial.GetSelfIllumColorOn(0, false);
                var maxSpecularColor = materialNode.MaxMaterial.GetSpecular(0, false).ToArray();

                if (isUnlit == false)
                {
                    babylonMaterial.ambient       = materialNode.MaxMaterial.GetAmbient(0, false).ToArray();
                    babylonMaterial.specular      = maxSpecularColor.Multiply(materialNode.MaxMaterial.GetShinStr(0, false));
                    babylonMaterial.specularPower = materialNode.MaxMaterial.GetShininess(0, false) * 256;
                    babylonMaterial.emissive      =
                        isSelfIllumColor
                            ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
                            : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false)); // compute the pre-multiplied emissive color

                    // If Self-Illumination color checkbox is checked
                    // Then self-illumination is assumed to be pre-multiplied
                    // Otherwise self-illumination needs to be multiplied with diffuse
                    // linkEmissiveWithDiffuse attribute tells the Babylon engine to perform such multiplication
                    babylonMaterial.linkEmissiveWithDiffuse = !isSelfIllumColor;
                    // useEmissiveAsIllumination attribute tells the Babylon engine to use pre-multiplied emissive as illumination
                    babylonMaterial.useEmissiveAsIllumination = isSelfIllumColor;

                    // Store the emissive value (before multiplication) for gltf
                    babylonMaterial.selfIllum = materialNode.MaxMaterial.GetSelfIllum(0, false);
                }

                // Textures

                BabylonFresnelParameters fresnelParameters;
                babylonMaterial.diffuseTexture = ExportTexture(stdMat, 1, out fresnelParameters, babylonScene);                // Diffuse
                if (fresnelParameters != null)
                {
                    babylonMaterial.diffuseFresnelParameters = fresnelParameters;
                }
                if ((babylonMaterial.alpha == 1.0f && babylonMaterial.opacityTexture == null) &&
                    babylonMaterial.diffuseTexture != null &&
                    (babylonMaterial.diffuseTexture.originalPath.EndsWith(".tif") || babylonMaterial.diffuseTexture.originalPath.EndsWith(".tiff")) &&
                    babylonMaterial.diffuseTexture.hasAlpha)
                {
                    RaiseWarning($"Diffuse texture named {babylonMaterial.diffuseTexture.originalPath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 2);
                    RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 2);
                }

                babylonMaterial.opacityTexture = ExportTexture(stdMat, 6, out fresnelParameters, babylonScene, false, true);   // Opacity
                if (fresnelParameters != null)
                {
                    babylonMaterial.opacityFresnelParameters = fresnelParameters;
                    if (babylonMaterial.alpha == 1 &&
                        babylonMaterial.opacityTexture == null)
                    {
                        babylonMaterial.alpha = 0;
                    }
                }

                if (isUnlit == false)
                {
                    babylonMaterial.ambientTexture = ExportTexture(stdMat, 0, out fresnelParameters, babylonScene);                // Ambient

                    babylonMaterial.specularTexture = ExportSpecularTexture(materialNode, maxSpecularColor, babylonScene);

                    babylonMaterial.emissiveTexture = ExportTexture(stdMat, 5, out fresnelParameters, babylonScene);               // Emissive
                    if (fresnelParameters != null)
                    {
                        babylonMaterial.emissiveFresnelParameters = fresnelParameters;
                        if (babylonMaterial.emissive[0] == 0 &&
                            babylonMaterial.emissive[1] == 0 &&
                            babylonMaterial.emissive[2] == 0 &&
                            babylonMaterial.emissiveTexture == null)
                        {
                            babylonMaterial.emissive = new float[] { 1, 1, 1 };
                        }
                    }

                    babylonMaterial.bumpTexture       = ExportTexture(stdMat, 8, out fresnelParameters, babylonScene);             // Bump
                    babylonMaterial.reflectionTexture = ExportTexture(stdMat, 9, out fresnelParameters, babylonScene, true);       // Reflection
                    if (fresnelParameters != null)
                    {
                        if (babylonMaterial.reflectionTexture == null)
                        {
                            RaiseWarning("Fallout cannot be used with reflection channel without a texture", 2);
                        }
                        else
                        {
                            babylonMaterial.reflectionFresnelParameters = fresnelParameters;
                        }
                    }
                }

                // Constraints
                if (babylonMaterial.diffuseTexture != null)
                {
                    babylonMaterial.diffuse = new[] { 1.0f, 1.0f, 1.0f };
                }

                if (babylonMaterial.emissiveTexture != null)
                {
                    babylonMaterial.emissive = new float[] { 0, 0, 0 };
                }

                if (babylonMaterial.opacityTexture != null && babylonMaterial.diffuseTexture != null &&
                    babylonMaterial.diffuseTexture.name == babylonMaterial.opacityTexture.name &&
                    babylonMaterial.diffuseTexture.hasAlpha && !babylonMaterial.opacityTexture.getAlphaFromRGB)
                {
                    // This is a alpha testing purpose
                    babylonMaterial.opacityTexture          = null;
                    babylonMaterial.diffuseTexture.hasAlpha = true;
                    RaiseWarning("Opacity texture was removed because alpha from diffuse texture can be use instead", 2);
                    RaiseWarning("If you do not want this behavior, just set Alpha Source = None on your diffuse texture", 2);
                }

                babylonScene.MaterialsList.Add(babylonMaterial);
            }
            else if (isPhysicalMaterial(materialNode))
            {
                var propertyContainer = materialNode.IPropertyContainer;

                var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial
                {
                    name    = name,
                    id      = id,
                    isUnlit = isUnlit
                };

                // --- Global ---

                // Alpha
                //var alphaFromXParency = 1.0f - materialNode.MaxMaterial.GetXParency(0, false);
                var alphaFromPropertyContainer = 1.0f - propertyContainer.GetFloatProperty(17);
                //RaiseMessage("alphaFromXParency=" + alphaFromXParency, 2);
                //RaiseMessage("alphaFromPropertyContainer=" + alphaFromPropertyContainer, 2);
                babylonMaterial.alpha = alphaFromPropertyContainer;

                babylonMaterial.baseColor = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray();

                var invertRoughness = propertyContainer.GetBoolProperty(5);
                if (isUnlit == false)
                {
                    babylonMaterial.metallic = propertyContainer.GetFloatProperty(6);

                    babylonMaterial.roughness = propertyContainer.GetFloatProperty(4);
                    if (invertRoughness)
                    {
                        // Inverse roughness
                        babylonMaterial.roughness = 1 - babylonMaterial.roughness;
                    }

                    // Self illumination is computed from emission color, luminance, temperature and weight
                    babylonMaterial.emissive = materialNode.MaxMaterial.GetSelfIllumColorOn(0, false)
                                                    ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
                                                    : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false));
                }
                else
                {
                    // Ignore specified roughness and metallic values
                    babylonMaterial.metallic  = 0;
                    babylonMaterial.roughness = 0.9f;
                }

                // --- Textures ---
                // 1 - base color ; 9 - transparancy weight
                ITexmap colorTexmap = _getTexMap(materialNode, 1);
                ITexmap alphaTexmap = _getTexMap(materialNode, 9);
                babylonMaterial.baseTexture = ExportBaseColorAlphaTexture(colorTexmap, alphaTexmap, babylonMaterial.baseColor, babylonMaterial.alpha, babylonScene, name);

                if (isUnlit == false)
                {
                    // Metallic, roughness, ambient occlusion
                    ITexmap metallicTexmap         = _getTexMap(materialNode, 5);
                    ITexmap roughnessTexmap        = _getTexMap(materialNode, 4);
                    ITexmap ambientOcclusionTexmap = _getTexMap(materialNode, 6); // Use diffuse roughness map as ambient occlusion

                    // Check if MR or ORM textures are already merged
                    bool areTexturesAlreadyMerged = false;
                    if (metallicTexmap != null && roughnessTexmap != null)
                    {
                        string sourcePathMetallic  = getSourcePath(metallicTexmap);
                        string sourcePathRoughness = getSourcePath(roughnessTexmap);

                        if (sourcePathMetallic == sourcePathRoughness)
                        {
                            if (ambientOcclusionTexmap != null && exportParameters.mergeAOwithMR)
                            {
                                string sourcePathAmbientOcclusion = getSourcePath(ambientOcclusionTexmap);
                                if (sourcePathMetallic == sourcePathAmbientOcclusion)
                                {
                                    // Metallic, roughness and ambient occlusion are already merged
                                    RaiseVerbose("Metallic, roughness and ambient occlusion are already merged", 2);
                                    BabylonTexture ormTexture = ExportTexture(metallicTexmap, babylonScene);
                                    babylonMaterial.metallicRoughnessTexture = ormTexture;
                                    babylonMaterial.occlusionTexture         = ormTexture;
                                    areTexturesAlreadyMerged = true;
                                }
                            }
                            else
                            {
                                // Metallic and roughness are already merged
                                RaiseVerbose("Metallic and roughness are already merged", 2);
                                BabylonTexture ormTexture = ExportTexture(metallicTexmap, babylonScene);
                                babylonMaterial.metallicRoughnessTexture = ormTexture;
                                areTexturesAlreadyMerged = true;
                            }
                        }
                    }
                    if (areTexturesAlreadyMerged == false)
                    {
                        if (metallicTexmap != null || roughnessTexmap != null)
                        {
                            // Merge metallic, roughness and ambient occlusion
                            RaiseVerbose("Merge metallic and roughness (and ambient occlusion if `mergeAOwithMR` is enabled)", 2);
                            BabylonTexture ormTexture = ExportORMTexture(exportParameters.mergeAOwithMR ? ambientOcclusionTexmap : null, roughnessTexmap, metallicTexmap, babylonMaterial.metallic, babylonMaterial.roughness, babylonScene, invertRoughness);
                            babylonMaterial.metallicRoughnessTexture = ormTexture;

                            if (ambientOcclusionTexmap != null)
                            {
                                if (exportParameters.mergeAOwithMR)
                                {
                                    babylonMaterial.occlusionTexture = ormTexture;
                                }
                                else
                                {
                                    babylonMaterial.occlusionTexture = ExportPBRTexture(materialNode, 6, babylonScene);
                                }
                            }
                        }
                        else if (ambientOcclusionTexmap != null)
                        {
                            // Simply export occlusion texture
                            RaiseVerbose("Simply export occlusion texture", 2);
                            babylonMaterial.occlusionTexture = ExportTexture(ambientOcclusionTexmap, babylonScene);
                        }
                    }
                    if (ambientOcclusionTexmap != null && !exportParameters.mergeAOwithMR && babylonMaterial.occlusionTexture == null)
                    {
                        RaiseVerbose("Exporting occlusion texture without merging with metallic roughness", 2);
                        babylonMaterial.occlusionTexture = ExportTexture(ambientOcclusionTexmap, babylonScene);
                    }

                    var normalMapAmount = propertyContainer.GetFloatProperty(91);
                    babylonMaterial.normalTexture = ExportPBRTexture(materialNode, 30, babylonScene, normalMapAmount);

                    babylonMaterial.emissiveTexture = ExportPBRTexture(materialNode, 17, babylonScene);
                }


                if (babylonMaterial.alpha != 1.0f || (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha))
                {
                    var  alphaTestProperty = materialNode.IPropertyContainer.QueryProperty("BabylonAlphaTest");
                    bool isAlphaTest       = alphaTestProperty != null?alphaTestProperty.GetBoolValue() : false;

                    babylonMaterial.transparencyMode = isAlphaTest ? (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHATEST : (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND;
                }

                if (babylonMaterial.emissiveTexture != null)
                {
                    babylonMaterial.emissive = new[] { 1.0f, 1.0f, 1.0f };
                }

                if (babylonMaterial.metallicRoughnessTexture != null)
                {
                    babylonMaterial.metallic  = 1.0f;
                    babylonMaterial.roughness = 1.0f;
                }

                babylonScene.MaterialsList.Add(babylonMaterial);
            }
            else if (isArnoldMaterial(materialNode))
            {
                var propertyContainer = materialNode.IPropertyContainer;
                var babylonMaterial   = new BabylonPBRMetallicRoughnessMaterial
                {
                    name    = name,
                    id      = id,
                    isUnlit = isUnlit
                };

                // Alpha
                babylonMaterial.alpha = 1.0f - propertyContainer.GetFloatProperty(32);

                // Color: base * weight
                float[] baseColor  = propertyContainer.GetPoint3Property(5).ToArray();
                float   baseWeight = propertyContainer.GetFloatProperty(2);
                babylonMaterial.baseColor = baseColor.Multiply(baseWeight);

                // Metallic & roughness
                bool invertRoughness = false;
                babylonMaterial.roughness = propertyContainer.GetFloatProperty(17); // specular_roughness
                babylonMaterial.metallic  = propertyContainer.GetFloatProperty(29);

                // Emissive: emission_color * emission
                float[] emissionColor  = propertyContainer.GetPoint3Property(94).ToArray();
                float   emissionWeight = propertyContainer.GetFloatProperty(91);
                babylonMaterial.emissive = emissionColor.Multiply(emissionWeight);

                // --- Textures ---
                // 1 - base_color ; 5 - diffuse_roughness ; 9 - metalness ; 10 - transparent
                ITexmap colorTexmap = _getTexMap(materialNode, 1);
                ITexmap alphaTexmap = _getTexMap(materialNode, 10);
                babylonMaterial.baseTexture = ExportBaseColorAlphaTexture(colorTexmap, alphaTexmap, babylonMaterial.baseColor, babylonMaterial.alpha, babylonScene, name);

                if (isUnlit == false)
                {
                    // Metallic, roughness
                    ITexmap metallicTexmap  = _getTexMap(materialNode, 9);
                    ITexmap roughnessTexmap = _getTexMap(materialNode, 5);

                    // Check if MR textures are already merged
                    bool areTexturesAlreadyMerged = false;
                    if (metallicTexmap != null && roughnessTexmap != null)
                    {
                        string sourcePathMetallic  = getSourcePath(metallicTexmap);
                        string sourcePathRoughness = getSourcePath(roughnessTexmap);

                        if (sourcePathMetallic == sourcePathRoughness)
                        {
                            // Metallic and roughness are already merged
                            RaiseVerbose("Metallic and roughness are already merged", 2);
                            BabylonTexture ormTexture = ExportTexture(metallicTexmap, babylonScene);
                            babylonMaterial.metallicRoughnessTexture = ormTexture;
                            // The already merged map is assumed to contain Ambient Occlusion in R channel
                            babylonMaterial.occlusionTexture = ormTexture;
                            areTexturesAlreadyMerged         = true;
                        }
                    }
                    if (areTexturesAlreadyMerged == false)
                    {
                        if (metallicTexmap != null || roughnessTexmap != null)
                        {
                            // Merge metallic, roughness
                            RaiseVerbose("Merge metallic and roughness", 2);
                            BabylonTexture ormTexture = ExportORMTexture(null, roughnessTexmap, metallicTexmap, babylonMaterial.metallic, babylonMaterial.roughness, babylonScene, invertRoughness);
                            babylonMaterial.metallicRoughnessTexture = ormTexture;
                        }
                    }

                    babylonMaterial.normalTexture   = ExportPBRTexture(materialNode, 20, babylonScene);
                    babylonMaterial.emissiveTexture = ExportPBRTexture(materialNode, 30, babylonScene);
                }

                // Constraints
                if (babylonMaterial.baseTexture != null)
                {
                    babylonMaterial.baseColor = new[] { 1.0f, 1.0f, 1.0f };
                    babylonMaterial.alpha     = 1.0f;
                }

                if (babylonMaterial.alpha != 1.0f || (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha))
                {
                    babylonMaterial.transparencyMode = (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND;
                }

                if (babylonMaterial.emissiveTexture != null)
                {
                    babylonMaterial.emissive = new[] { 1.0f, 1.0f, 1.0f };
                }

                if (babylonMaterial.metallicRoughnessTexture != null)
                {
                    babylonMaterial.metallic  = 1.0f;
                    babylonMaterial.roughness = 1.0f;
                }

                // Add the material to the scene
                babylonScene.MaterialsList.Add(babylonMaterial);
            }
            else
            {
                // isMaterialExportable check should prevent this to happen
                RaiseError("Unsupported material type: " + materialNode.MaterialClass, 2);
            }
        }