예제 #1
0
        private Schema.MaterialPbrSpecularGlossiness ConvertMaterialPbrSpecularGlossiness(KHR_materials_pbrSpecularGlossiness runtimeMaterial)
        {
            var material = CreateInstance <Schema.MaterialPbrSpecularGlossiness>();

            if (runtimeMaterial.DiffuseFactor.HasValue)
            {
                material.DiffuseFactor = runtimeMaterial.DiffuseFactor.Value.ToArray();
            }

            if (runtimeMaterial.DiffuseTexture != null)
            {
                material.DiffuseTexture = ConvertTextureInfo(runtimeMaterial.DiffuseTexture);
            }

            if (runtimeMaterial.SpecularFactor.HasValue)
            {
                material.SpecularFactor = runtimeMaterial.SpecularFactor.Value.ToArray();
            }

            if (runtimeMaterial.GlossinessFactor.HasValue)
            {
                material.GlossinessFactor = runtimeMaterial.GlossinessFactor.Value;
            }

            if (runtimeMaterial.SpecularGlossinessTexture != null)
            {
                material.SpecularGlossinessTexture = ConvertTextureInfo(runtimeMaterial.SpecularGlossinessTexture);
            }

            return(material);
        }
        public Material_SpecularGlossiness(List <string> imageList)
        {
            Runtime.Image diffuseTextureImage            = UseTexture(imageList, "Diffuse_Plane");
            Runtime.Image specularGlossinessTextureImage = UseTexture(imageList, "SpecularGlossiness_Plane");
            Runtime.Image baseColorTextureImage          = UseTexture(imageList, "BaseColor_X");

            // Track the common properties for use in the readme.
            CommonProperties.Add(new Property(PropertyName.ExtensionUsed, "Specular Glossiness"));
            CommonProperties.Add(new Property(PropertyName.ExtensionRequired, "Specular Glossiness"));
            CommonProperties.Add(new Property(PropertyName.BaseColorTexture, baseColorTextureImage));

            Model CreateModel(Action <List <Property>, Runtime.MeshPrimitive, Runtime.Material, KHR_materials_pbrSpecularGlossiness> setProperties)
            {
                var properties    = new List <Property>();
                var meshPrimitive = MeshPrimitive.CreateSinglePlane();
                var extension     = new KHR_materials_pbrSpecularGlossiness();

                meshPrimitive.Material            = new Runtime.Material();
                meshPrimitive.Material.Extensions = new List <Extension> {
                    extension
                };
                meshPrimitive.Material.MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness();

                // Apply the common properties to the gltf.
                meshPrimitive.Material.MetallicRoughnessMaterial.BaseColorTexture = new Runtime.Texture {
                    Source = baseColorTextureImage
                };

                // Apply the properties that are specific to this gltf.
                setProperties(properties, meshPrimitive, meshPrimitive.Material, extension);

                // Create the gltf object.
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF(() => new Runtime.Scene
                    {
                        Nodes = new[]
                        {
                            new Runtime.Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = new[]
                                    {
                                        meshPrimitive
                                    }
                                },
                            },
                        },
                    },
                                      extensionsUsed: new List <string> {
                        "KHR_materials_pbrSpecularGlossiness"
                    },
                                      extensionsRequired: new List <string> {
                        "KHR_materials_pbrSpecularGlossiness"
                    }),
                });
            }

            void SetVertexColor(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                var vertexColors = new[]
                {
                    new Vector4(0.0f, 0.0f, 1.0f, 0.8f),
                    new Vector4(1.0f, 0.0f, 0.0f, 0.8f),
                    new Vector4(0.0f, 0.0f, 1.0f, 0.8f),
                    new Vector4(1.0f, 0.0f, 0.0f, 0.8f)
                };

                meshPrimitive.ColorComponentType = ColorComponentTypeEnum.FLOAT;
                meshPrimitive.ColorType          = ColorTypeEnum.VEC3;
                meshPrimitive.Colors             = vertexColors;

                properties.Add(new Property(PropertyName.VertexColor, "Vector3 Float"));
            }

            void SetDiffuseTexture(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                extension.DiffuseTexture = new Runtime.Texture {
                    Source = diffuseTextureImage
                };
                properties.Add(new Property(PropertyName.DiffuseTexture, diffuseTextureImage));
            }

            void SetDiffuseFactor(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                var diffuseFactorValue = new Vector4(0.2f, 0.2f, 0.2f, 0.8f);

                extension.DiffuseFactor = diffuseFactorValue;
                properties.Add(new Property(PropertyName.DiffuseFactor, diffuseFactorValue));
            }

            void SetSpecularGlossinessTexture(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                extension.SpecularGlossinessTexture = new Runtime.Texture {
                    Source = specularGlossinessTextureImage
                };
                properties.Add(new Property(PropertyName.SpecularGlossinessTexture, specularGlossinessTextureImage));
            }

            void SetSpecularFactor(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                var specularFactorValue = new Vector3(0.4f, 0.4f, 0.4f);

                extension.SpecularFactor = specularFactorValue;
                properties.Add(new Property(PropertyName.SpecularFactor, specularFactorValue));
            }

            void SetSpecularFactorToZero(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                var specularFactorValue = new Vector3(0.0f, 0.0f, 0.0f);

                extension.SpecularFactor = specularFactorValue;
                properties.Add(new Property(PropertyName.SpecularFactor, specularFactorValue));
            }

            void SetGlossinessFactor(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                extension.GlossinessFactor = 0.3f;
                properties.Add(new Property(PropertyName.GlossinessFactor, extension.GlossinessFactor));
            }

            Models = new List <Model>
            {
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    // There are no properties set on this model.
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetVertexColor(properties, meshPrimitive);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseTexture(properties, extension);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseFactor(properties, extension);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetSpecularGlossinessTexture(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetSpecularFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetGlossinessFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetVertexColor(properties, meshPrimitive);
                    SetDiffuseTexture(properties, extension);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseTexture(properties, extension);
                    SetDiffuseFactor(properties, extension);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseTexture(properties, extension);
                    SetGlossinessFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetSpecularGlossinessTexture(properties, extension);
                    SetSpecularFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetSpecularGlossinessTexture(properties, extension);
                    SetGlossinessFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseTexture(properties, extension);
                    SetSpecularFactor(properties, extension);
                    SetGlossinessFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetVertexColor(properties, meshPrimitive);
                    SetDiffuseTexture(properties, extension);
                    SetDiffuseFactor(properties, extension);
                    SetSpecularGlossinessTexture(properties, extension);
                    SetSpecularFactor(properties, extension);
                    SetGlossinessFactor(properties, extension);
                }),
            };

            GenerateUsedPropertiesList();
        }
예제 #3
0
        public Compatibility(List <string> imageList)
        {
            NoSampleImages = true;

            // There are no common properties in this model group.

            Model CreateModel(Action <List <Property>, Asset, List <string>, List <string>, Runtime.MeshPrimitive> setProperties,
                              Action <Schema.Gltf> postRuntimeChanges = null, Dictionary <Type, Type> schemaTypeMapping = null, bool?setLoadableTag = true)
            {
                var properties = new List <Property>();

                var gltf = CreateGLTF(() => new Scene());

                Runtime.MeshPrimitive meshPrimitive = MeshPrimitive.CreateSinglePlane(includeTextureCoords: false);
                var extensionsUsed     = new List <string>();
                var extensionsRequired = new List <string>();

                // Apply the properties that are specific to this gltf.
                setProperties(properties, gltf.Asset, extensionsUsed, extensionsRequired, meshPrimitive);

                // Create the gltf object.
                if (extensionsUsed.Any())
                {
                    gltf.ExtensionsUsed = extensionsUsed;
                }
                if (extensionsRequired.Any())
                {
                    gltf.ExtensionsRequired = extensionsRequired;
                }

                gltf.Scenes.First().Nodes = new List <Node>
                {
                    new Node
                    {
                        Mesh = new Runtime.Mesh
                        {
                            MeshPrimitives = new List <Runtime.MeshPrimitive>
                            {
                                meshPrimitive
                            }
                        },
                    },
                };

                var model = new Model
                {
                    Properties = properties,
                    GLTF       = gltf
                };

                model.Loadable           = setLoadableTag;
                model.PostRuntimeChanges = postRuntimeChanges;

                if (schemaTypeMapping != null)
                {
                    model.CreateSchemaInstance = type =>
                    {
                        if (schemaTypeMapping.TryGetValue(type, out Type mappedType))
                        {
                            type = mappedType;
                        }

                        return(Activator.CreateInstance(type));
                    };
                }

                return(model);
            }

            Property SetMinVersion(Asset asset)
            {
                return(new Property(PropertyName.MinVersion, asset.MinVersion = "2.1"));
            }

            Property SetVersionCurrent(Asset asset)
            {
                return(new Property(PropertyName.Version, asset.Version = "2.0"));
            }

            Property SetVersionFuture(Asset asset)
            {
                return(new Property(PropertyName.Version, asset.Version = "2.1"));
            }

            void SetPostRuntimeAtRoot(Schema.Gltf gltf)
            {
                // Add an simulated feature at the root level.
                var experimentalGltf = (ExperimentalGltf)gltf;

                experimentalGltf.Lights = new[]
                {
                    new ExperimentalLight
                    {
                        Color = new[] { 0.3f, 0.4f, 0.5f }
                    }
                };
            }

            void SetPostRuntimeInProperty(Schema.Gltf gltf)
            {
                // Add an simulated feature into an existing property.
                var experimentalNode = (ExperimentalNode)gltf.Nodes[0];

                experimentalNode.Light = 0;
            }

            void SetPostRuntimeWithFallback(Schema.Gltf gltf)
            {
                // Add an simulated feature with a fallback option.
                gltf.Materials = new Schema.Material[]
                {
                    new ExperimentalMaterial
                    {
                        AlphaMode  = Schema.Material.AlphaModeEnum.BLEND,
                        AlphaMode2 = ExperimentalAlphaMode2.QUANTUM,
                    }
                };
            }

            var experimentalSchemaTypeMapping = new Dictionary <Type, Type>
            {
                { typeof(Schema.Gltf), typeof(ExperimentalGltf) },
                { typeof(Schema.Node), typeof(ExperimentalNode) },
                { typeof(Schema.Material), typeof(ExperimentalMaterial) },
            };

            var shouldLoad = ":white_check_mark:";

            Models = new List <Model>
            {
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionCurrent(asset));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionFuture(asset));
                    properties.Add(new Property(PropertyName.Description, "Light object added at root"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }, SetPostRuntimeAtRoot, experimentalSchemaTypeMapping),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionFuture(asset));
                    properties.Add(new Property(PropertyName.Description, "Light property added to node object"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }, SetPostRuntimeInProperty, experimentalSchemaTypeMapping),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionFuture(asset));
                    properties.Add(new Property(PropertyName.Description, "Alpha mode updated with a new enum value, and a fallback value"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }, SetPostRuntimeWithFallback, experimentalSchemaTypeMapping),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetMinVersion(asset));
                    properties.Add(SetVersionFuture(asset));
                    properties.Add(new Property(PropertyName.Description, "Requires a specific version or higher"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, "Only in version 2.1 or higher"));
                }, null, null, setLoadableTag: false),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionCurrent(asset));

                    var emptyTexture = new Texture();
                    var extension    = new FAKE_materials_quantumRendering
                    {
                        PlanckFactor      = new Vector4(0.2f, 0.2f, 0.2f, 0.8f),
                        CopenhagenTexture = new TextureInfo
                        {
                            Texture = emptyTexture
                        },
                        EntanglementFactor           = new Vector3(0.4f, 0.4f, 0.4f),
                        ProbabilisticFactor          = 0.3f,
                        SuperpositionCollapseTexture = new TextureInfo
                        {
                            Texture = emptyTexture
                        },
                    };

                    meshPrimitive.Material = new Runtime.Material
                    {
                        Extensions = new List <Extension>
                        {
                            extension
                        }
                    };

                    extensionsUsed.Add(extension.Name);
                    extensionsRequired.Add(extension.Name);

                    properties.Add(new Property(PropertyName.Description, "Extension required"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, ":x:"));
                }, null, null, setLoadableTag: false),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionCurrent(asset));

                    var extension = new KHR_materials_pbrSpecularGlossiness
                    {
                        SpecularFactor   = new Vector3(0.04f, 0.04f, 0.04f),
                        GlossinessFactor = 0.0f,
                    };

                    meshPrimitive.Material = new Runtime.Material
                    {
                        // Metallic-Roughness
                        PbrMetallicRoughness = new PbrMetallicRoughness
                        {
                            MetallicFactor = 0.0f
                        },
                        // Specular-Glossiness
                        Extensions = new[] { extension },
                    };

                    extensionsUsed.Add(extension.Name);

                    properties.Add(new Property(PropertyName.Description, "Specular Glossiness extension used but not required"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }),
            };

            GenerateUsedPropertiesList();
        }
예제 #4
0
        private void ExportMaterial(BabylonMaterial babylonMaterial, GLTF gltf)
        {
            var name = babylonMaterial.name;
            var id   = babylonMaterial.id;

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

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

            if (customMaterialExporter != null && customMaterialExporter.GetGltfMaterial(babylonMaterial, gltf, logger, out gltfMaterial))
            {
                gltfMaterial.index = gltf.MaterialsList.Count;
                gltf.MaterialsList.Add(gltfMaterial);
            }
            else if (babylonMaterial is BabylonStandardMaterial babylonStandardMaterial)
            {
                // --- prints ---
                #region prints

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

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

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

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

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

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

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

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

                // --------------------------------
                // --------- gltfMaterial ---------
                // --------------------------------
                logger.RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
                gltfMaterial = new GLTFMaterial
                {
                    name = name
                };
                gltfMaterial.id    = babylonMaterial.id;
                gltfMaterial.index = gltf.MaterialsList.Count;
                gltf.MaterialsList.Add(gltfMaterial);

                //Custom user properties
                if (babylonStandardMaterial.metadata != null && babylonStandardMaterial.metadata.Count != 0)
                {
                    gltfMaterial.extras = babylonStandardMaterial.metadata;
                }

                // Alpha
                GLTFMaterial.AlphaMode alphaMode;
                float?alphaCutoff;
                getAlphaMode(babylonStandardMaterial, out alphaMode, out alphaCutoff);
                gltfMaterial.alphaMode = alphaMode;
                if (alphaCutoff.HasValue && alphaCutoff.Value != 0.5f) // do not export glTF default value
                {
                    gltfMaterial.alphaCutoff = alphaCutoff;
                }

                // DoubleSided
                gltfMaterial.doubleSided = !babylonMaterial.backFaceCulling;

                // Normal
                gltfMaterial.normalTexture = ExportTexture(babylonStandardMaterial.bumpTexture, gltf);

                // Occlusion
                gltfMaterial.occlusionTexture = ExportTexture(babylonStandardMaterial.ambientTexture, gltf);

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

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

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

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

                // --- Global ---

                SpecularGlossiness _specularGlossiness = new SpecularGlossiness
                {
                    diffuse    = new BabylonColor3(babylonStandardMaterial.diffuse),
                    opacity    = babylonMaterial.alpha,
                    specular   = new BabylonColor3(babylonStandardMaterial.specular),
                    glossiness = babylonStandardMaterial.specularPower / 256
                };

                MetallicRoughness _metallicRoughness = ConvertToMetallicRoughness(_specularGlossiness, true);

                // Base color
                gltfPbrMetallicRoughness.baseColorFactor = new float[4]
                {
                    _metallicRoughness.baseColor.r,
                    _metallicRoughness.baseColor.g,
                    _metallicRoughness.baseColor.b,
                    _metallicRoughness.opacity
                };

                // Metallic roughness
                gltfPbrMetallicRoughness.metallicFactor  = _metallicRoughness.metallic;
                gltfPbrMetallicRoughness.roughnessFactor = _metallicRoughness.roughness;


                // --- Textures ---
                var babylonTexture = babylonStandardMaterial.diffuseTexture != null ? babylonStandardMaterial.diffuseTexture :
                                     babylonStandardMaterial.specularTexture != null ? babylonStandardMaterial.specularTexture :
                                     babylonStandardMaterial.opacityTexture != null ? babylonStandardMaterial.opacityTexture :
                                     null;

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

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

                        Bitmap baseColorBitmap             = null;
                        Bitmap metallicRoughnessBitmap     = null;
                        string baseColorBitmapName         = null;
                        string metallicRoughnessBitmapName = null;

                        GLTFTextureInfo textureInfoBC = null;
                        GLTFTextureInfo textureInfoMR = null;

                        if (exportParameters.writeTextures)
                        {
                            // Diffuse
                            Bitmap diffuseBitmap = null;
                            if (babylonStandardMaterial.diffuseTexture != null)
                            {
                                if (babylonStandardMaterial.diffuseTexture.bitmap != null)
                                {
                                    // Diffuse color map has been computed by the exporter
                                    diffuseBitmap = babylonStandardMaterial.diffuseTexture.bitmap;
                                }
                                else
                                {
                                    // Diffuse color map is straight input
                                    diffuseBitmap = TextureUtilities.LoadTexture(babylonStandardMaterial.diffuseTexture.originalPath, logger);
                                    babylonStandardMaterial.diffuseTexture.bitmap = diffuseBitmap;
                                }
                            }

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

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

                            if ((diffuseBitmap != null && (specularBitmap != null || opacityBitmap != null)) || specularBitmap != null || opacityBitmap != null)
                            {
                                // Retreive dimensions
                                int width              = 0;
                                int height             = 0;
                                var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, diffuseBitmap, specularBitmap, opacityBitmap);
                                if (!haveSameDimensions)
                                {
                                    logger.RaiseError("Diffuse, specular and opacity maps should have same dimensions", 2);
                                }
                                baseColorBitmapName = (babylonStandardMaterial.diffuseTexture != null ? Path.GetFileNameWithoutExtension(babylonStandardMaterial.diffuseTexture.name) : TextureUtilities.ColorToStringName(Color.FromArgb(255, (int)(babylonStandardMaterial.diffuse[0]), (int)(babylonStandardMaterial.diffuse[1]), (int)(babylonStandardMaterial.diffuse[2]))))
                                                      + (babylonStandardMaterial.opacityTexture != null ? "_alpha_" + Path.GetFileNameWithoutExtension(babylonStandardMaterial.opacityTexture.name) : "")
                                                      + ".png";

                                metallicRoughnessBitmapName = "MR_" + baseColorBitmapName
                                                              + "_spec_" + (babylonStandardMaterial.specularTexture != null ? Path.GetFileNameWithoutExtension(babylonStandardMaterial.specularTexture.name) : TextureUtilities.ColorToStringName(Color.FromArgb(255, (int)(babylonStandardMaterial.specular[0]), (int)(babylonStandardMaterial.specular[1]), (int)(babylonStandardMaterial.specular[2]))))
                                                              + "_gloss_" + babylonStandardMaterial.specularPower
                                                              + ".png";
                                // Create baseColor+alpha and metallic+roughness maps
                                baseColorBitmap         = new Bitmap(width, height);
                                metallicRoughnessBitmap = new Bitmap(width, height);
                                for (int x = 0; x < width; x++)
                                {
                                    for (int y = 0; y < height; y++)
                                    {
                                        SpecularGlossiness specularGlossinessTexture = new SpecularGlossiness
                                        {
                                            diffuse = diffuseBitmap != null ? new BabylonColor3(diffuseBitmap.GetPixel(x, y)) :
                                                      _specularGlossiness.diffuse,
                                            opacity = diffuseBitmap != null && babylonStandardMaterial.diffuseTexture.hasAlpha ? diffuseBitmap.GetPixel(x, y).A / 255.0f :
                                                      opacityBitmap != null && babylonStandardMaterial.opacityTexture.getAlphaFromRGB ? opacityBitmap.GetPixel(x, y).R / 255.0f :
                                                      opacityBitmap != null && babylonStandardMaterial.opacityTexture.getAlphaFromRGB == false?opacityBitmap.GetPixel(x, y).A / 255.0f :
                                                      _specularGlossiness.opacity,
                                            specular = specularBitmap != null ? new BabylonColor3(specularBitmap.GetPixel(x, y)) :
                                                       _specularGlossiness.specular,
                                            glossiness = babylonStandardMaterial.useGlossinessFromSpecularMapAlpha && specularBitmap != null?specularBitmap.GetPixel(x, y).A / 255.0f :
                                                         _specularGlossiness.glossiness
                                        };

                                        var displayPrints = x == width / 2 && y == height / 2;
                                        MetallicRoughness metallicRoughnessTexture = ConvertToMetallicRoughness(specularGlossinessTexture, displayPrints);

                                        Color colorBase = Color.FromArgb(
                                            (int)(metallicRoughnessTexture.opacity * 255),
                                            (int)(metallicRoughnessTexture.baseColor.r * 255),
                                            (int)(metallicRoughnessTexture.baseColor.g * 255),
                                            (int)(metallicRoughnessTexture.baseColor.b * 255)
                                            );
                                        baseColorBitmap.SetPixel(x, y, colorBase);

                                        // The metalness values are sampled from the B channel.
                                        // The roughness values are sampled from the G channel.
                                        // These values are linear. If other channels are present (R or A), they are ignored for metallic-roughness calculations.
                                        Color colorMetallicRoughness = Color.FromArgb(
                                            0,
                                            (int)(metallicRoughnessTexture.roughness * 255),
                                            (int)(metallicRoughnessTexture.metallic * 255)
                                            );
                                        metallicRoughnessBitmap.SetPixel(x, y, colorMetallicRoughness);
                                    }
                                }
                            }
                        }

                        //export textures
                        if (baseColorBitmap != null || babylonTexture.bitmap != null)
                        {
                            textureInfoBC = ExportBitmapTexture(gltf, babylonTexture, baseColorBitmap, baseColorBitmapName);
                            gltfPbrMetallicRoughness.baseColorTexture = textureInfoBC;
                        }

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

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

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

                    if (gltfPbrMetallicRoughness.metallicRoughnessTexture != null)
                    {
                        gltfPbrMetallicRoughness.metallicFactor  = 1.0f;
                        gltfPbrMetallicRoughness.roughnessFactor = 1.0f;
                    }
                }
            }
            else if (typeof(BabylonPBRBaseSimpleMaterial).IsAssignableFrom(babylonMaterial.GetType()))
            {
                var babylonPBRBaseSimpleMaterial = babylonMaterial as BabylonPBRBaseSimpleMaterial;

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

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

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

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


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

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

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

                if (babylonMaterial is BabylonPBRMetallicRoughnessMaterial pbrMRMatPrint)
                {
                    // Metallic+roughness
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallic=" + pbrMRMatPrint.metallic, 3);
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.roughness=" + pbrMRMatPrint.roughness, 3);
                    if (pbrMRMatPrint.metallicRoughnessTexture == null)
                    {
                        logger.RaiseVerbose("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture=null", 3);
                    }
                }
                else if (babylonMaterial is BabylonPBRSpecularGlossinessMaterial pbrSGMatPrint)
                {
                    // Metallic+roughness
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRSpecularGlossinessMaterial.specular=" + pbrSGMatPrint.specularColor, 3);
                    logger.RaiseVerbose("GLTFExporter.Material | babylonPBRSpecularGlossinessMaterial.glossiness=" + pbrSGMatPrint.glossiness, 3);
                    if (pbrSGMatPrint.specularGlossinessTexture == null)
                    {
                        logger.RaiseVerbose("GLTFExporter.Material | babylonPBRSpecularGlossinessMaterial.specularGlossinessTexture=null", 3);
                    }
                }

                #endregion

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

                logger.RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
                gltfMaterial = new GLTFMaterial
                {
                    name = name
                };
                gltfMaterial.id    = babylonMaterial.id;
                gltfMaterial.index = gltf.MaterialsList.Count;
                gltf.MaterialsList.Add(gltfMaterial);

                //Custom user properties
                if (babylonMaterial.metadata != null && babylonMaterial.metadata.Count != 0)
                {
                    gltfMaterial.extras = babylonMaterial.metadata;
                }

                // Alpha
                GLTFMaterial.AlphaMode alphaMode;
                float?alphaCutoff;
                getAlphaMode(babylonPBRBaseSimpleMaterial, out alphaMode, out alphaCutoff);
                gltfMaterial.alphaMode = alphaMode;
                if (alphaCutoff.HasValue && alphaCutoff.Value != 0.5f) // do not export glTF default value
                {
                    gltfMaterial.alphaCutoff = alphaCutoff;
                }

                // DoubleSided
                gltfMaterial.doubleSided = babylonPBRBaseSimpleMaterial.doubleSided;

                // Normal
                gltfMaterial.normalTexture = ExportTexture(babylonPBRBaseSimpleMaterial.normalTexture, gltf);

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

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

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

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

                    // --- Global ---

                    // Base color
                    gltfPbrMetallicRoughness.baseColorFactor = new float[4]
                    {
                        pbrMRMat.baseColor[0],
                        pbrMRMat.baseColor[1],
                        pbrMRMat.baseColor[2],
                        pbrMRMat.alpha
                    };
                    if (pbrMRMat.baseTexture != null)
                    {
                        gltfPbrMetallicRoughness.baseColorTexture = ExportBaseColorTexture(gltf, pbrMRMat.baseTexture);
                    }

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

                            if (pbrMRMat.metallicRoughnessTexture.bitmap != null)
                            {
                                // Metallic & roughness texture has been merged manually by the exporter
                                // Write bitmap file
                                logger.RaiseVerbose("Metallic & roughness texture has been merged manually by the exporter", 2);
                                gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportBitmapTexture(gltf, pbrMRMat.metallicRoughnessTexture);
                            }
                            else
                            {
                                // Metallic & roughness texture was already merged
                                // Copy file
                                logger.RaiseVerbose("Metallic & roughness texture was already merged", 2);
                                gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportTexture(pbrMRMat.metallicRoughnessTexture, gltf);
                            }
                        }
                    }
                }
                else if (babylonMaterial is BabylonPBRSpecularGlossinessMaterial pbrSGMat)
                {
                    var ext = new KHR_materials_pbrSpecularGlossiness()
                    {
                        specularFactor            = pbrSGMat.specularColor,
                        glossinessFactor          = pbrSGMat.glossiness,
                        diffuseTexture            = ExportTexture(pbrSGMat.diffuseTexture, gltf),
                        specularGlossinessTexture = ExportTexture(pbrSGMat.specularGlossinessTexture, gltf)
                    };

                    gltfMaterial.extensions = gltfMaterial.extensions ?? new GLTFExtensions(); // ensure extensions exist
                    gltfMaterial.extensions.AddExtension(gltf, "KHR_materials_pbrSpecularGlossiness", ext);
                }
            }
            else if (babylonMaterial.GetType() == typeof(BabylonFurMaterial))
            {
                // TODO - Implement proper handling of BabylonFurMaterial once gLTF spec has support
                var babylonPBRFurMaterial = babylonMaterial as BabylonFurMaterial;

                gltfMaterial = new GLTFMaterial
                {
                    name = name
                };
                gltfMaterial.id    = babylonMaterial.id;
                gltfMaterial.index = gltf.MaterialsList.Count;
                gltf.MaterialsList.Add(gltfMaterial);

                //Custom user properties
                if (babylonPBRFurMaterial.metadata != null && babylonPBRFurMaterial.metadata.Count != 0)
                {
                    gltfMaterial.extras = babylonPBRFurMaterial.metadata;
                }
            }
            else
            {
                logger.RaiseWarning("GLTFExporter.Material | Unsupported material type: " + babylonMaterial.GetType(), 2);
            }

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