Example #1
0
        /// <summary>
        /// Export a normal texture from Unity to glTF.
        /// </summary>
        /// <param name="texture">Normal texture to export</param>
        /// <param name="material">Material the normal is used on</param>
        /// <param name="gltf">Context glTF to export to</param>
        /// <returns>glTF texture info</returns>
        protected static NormalTextureInfo ExportNormalTextureInfo(
            UnityEngine.Texture texture,
            UnityEngine.Material material,
            IGltfWritable gltf
            )
        {
            var texture2d = texture as Texture2D;

            if (texture2d == null)
            {
                return(null);
            }
            var imageExport = new NormalImageExport(texture2d);

            if (AddImageExport(gltf, imageExport, out var textureId))
            {
                var info = new NormalTextureInfo {
                    index = textureId,
                    // texCoord = 0 // TODO: figure out which UV set was used
                };

                if (material.HasProperty(MaterialGenerator.bumpScalePropId))
                {
                    info.scale = material.GetFloat(MaterialGenerator.bumpScalePropId);
                }
                return(info);
            }
            return(null);
        }
        static NormalTextureInfo ExportNormalTextureInfo(
            UnityEngine.Texture texture,
            TextureMapType textureMapType,
            UnityEngine.Material material,
            IGltfWritable gltf
            )
        {
            var imageId = gltf.AddImage(texture);

            if (imageId < 0)
            {
                return(null);
            }
            var textureId = gltf.AddTexture(imageId);
            var info      = new NormalTextureInfo {
                index = textureId,
                // texCoord = 0 // TODO: figure out which UV set was used
            };

            if (material.HasProperty(MaterialGenerator.bumpScalePropId))
            {
                info.scale = material.GetFloat(MaterialGenerator.bumpScalePropId);
            }

            return(info);
        }
        static void ExportUnlit(Material material, UnityEngine.Material uMaterial, IGltfWritable gltf, ICodeLogger logger)
        {
            gltf.RegisterExtensionUsage(Extension.MaterialsUnlit);
            material.extensions = material.extensions ?? new MaterialExtension();
            material.extensions.KHR_materials_unlit = new MaterialUnlit();

            var pbr = material.pbrMetallicRoughness ?? new PbrMetallicRoughness();

            if (uMaterial.HasProperty(k_Color))
            {
                pbr.baseColor = uMaterial.GetColor(k_Color);
            }

            if (uMaterial.HasProperty(k_MainTex))
            {
                var mainTex = uMaterial.GetTexture(k_MainTex);
                if (mainTex != null)
                {
                    if (mainTex is Texture2D)
                    {
                        pbr.baseColorTexture = ExportTextureInfo(mainTex, TextureMapType.Main, gltf);
                        ExportTextureTransform(pbr.baseColorTexture, uMaterial, k_MainTex, gltf);
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "main", material.name);
                    }
                }
            }

            material.pbrMetallicRoughness = pbr;
        }
Example #4
0
        /// <summary>
        /// Adds an ImageExport to the glTF.
        /// No conversions or channel swizzling
        /// </summary>
        /// <param name="gltf"></param>
        /// <param name="imageExport"></param>
        /// <param name="textureId"></param>
        /// <returns>glTF texture ID</returns>
        protected static bool AddImageExport(IGltfWritable gltf, ImageExportBase imageExport, out int textureId)
        {
            var imageId = gltf.AddImage(imageExport);

            if (imageId < 0)
            {
                textureId = -1;
                return(false);
            }

            var samplerId = gltf.AddSampler(imageExport.filterMode, imageExport.wrapModeU, imageExport.wrapModeV);

            textureId = gltf.AddTexture(imageId, samplerId);
            return(true);
        }
        static OcclusionTextureInfo ExportOcclusionTextureInfo(
            UnityEngine.Texture texture,
            UnityEngine.Material material,
            IGltfWritable gltf
            )
        {
            var texture2d = texture as Texture2D;

            if (texture2d == null)
            {
                return(null);
            }
            var imageExport = new ImageExport(texture2d);

            if (AddImageExport(gltf, imageExport, out var textureId))
            {
                return(new OcclusionTextureInfo {
                    index = textureId
                });
            }
            return(null);
        }
Example #6
0
        /// <summary>
        /// Export a Unity texture to a glTF.
        /// </summary>
        /// <param name="texture">Texture to export.</param>
        /// <param name="gltf">Context glTF to expor to</param>
        /// <param name="format">Desired image format</param>
        /// <returns>glTF texture info</returns>
        protected static TextureInfo ExportTextureInfo(
            UnityEngine.Texture texture,
            IGltfWritable gltf,
            ImageExportBase.Format format = ImageExportBase.Format.Unknown
            )
        {
            var texture2d = texture as Texture2D;

            if (texture2d == null)
            {
                return(null);
            }
            var imageExport = new ImageExport(texture2d, format);

            if (AddImageExport(gltf, imageExport, out var textureId))
            {
                return(new TextureInfo {
                    index = textureId,
                    // texCoord = 0 // TODO: figure out which UV set was used
                });
            }
            return(null);
        }
Example #7
0
        /// <summary>
        /// Converts a Unity material to a glTF material.
        /// </summary>
        /// <param name="uMaterial">Source material</param>
        /// <param name="material">Resulting material</param>
        /// <param name="gltf">Associated IGltfWriter. Is used for adding images and textures.</param>
        /// <param name="logger">Logger used for reporting</param>
        /// <returns>True if no errors occured, false otherwise</returns>
        public override bool ConvertMaterial(UnityEngine.Material uMaterial, out Material material, IGltfWritable gltf, ICodeLogger logger)
        {
            var success = true;

            material = new Material {
                name = uMaterial.name,
                pbrMetallicRoughness = new PbrMetallicRoughness {
                    metallicFactor  = 0,
                    roughnessFactor = 1.0f
                }
            };

            SetAlphaModeAndCutoff(uMaterial, material);
            material.doubleSided = IsDoubleSided(uMaterial);

            //
            // Emission
            //
            if (uMaterial.HasProperty(k_EmissiveColor))
            {
                var emissionColor = uMaterial.GetColor(k_EmissiveColor);

                // Clamp emissiveColor to 0..1
                var maxFactor = math.max(emissionColor.r, math.max(emissionColor.g, emissionColor.b));
                if (maxFactor > 1f)
                {
                    emissionColor.r /= maxFactor;
                    emissionColor.g /= maxFactor;
                    emissionColor.b /= maxFactor;
                    // TODO: use maxFactor as emissiveStrength (KHR_materials_emissive_strength)
                }

                material.emissive = emissionColor;
            }

            if (uMaterial.HasProperty(k_EmissionColorMap))
            {
                var emissionTex = uMaterial.GetTexture(k_EmissionColorMap);

                if (emissionTex != null)
                {
                    if (emissionTex is Texture2D)
                    {
                        material.emissiveTexture = ExportTextureInfo(emissionTex, gltf);
                        ExportTextureTransform(material.emissiveTexture, uMaterial, k_EmissionColorMap, gltf);
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "emission", material.name);
                        success = false;
                    }
                }
            }

            //
            // Normal Map
            //
            if (
                uMaterial.HasProperty(k_NormalMap) &&
                uMaterial.IsKeywordEnabled(k_KeywordNormalMapTangentSpace)
                )
            {
                var normalTex = uMaterial.GetTexture(k_NormalMap);

                if (normalTex != null)
                {
                    if (normalTex is Texture2D)
                    {
                        material.normalTexture = ExportNormalTextureInfo(normalTex, uMaterial, gltf);
                        ExportTextureTransform(material.normalTexture, uMaterial, k_NormalMap, gltf);
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "normal", uMaterial.name);
                        success = false;
                    }
                }
            }


            var mainTexProperty = uMaterial.HasProperty(k_BaseColorMap) ? k_BaseColorMap : k_MainTex;

            if (IsUnlit(uMaterial))
            {
                ExportUnlit(material, uMaterial, mainTexProperty, gltf, logger);
            }
            else
            {
                success &= ExportPbrMetallicRoughness(
                    uMaterial,
                    material,
                    gltf,
                    logger
                    );
            }



            return(success);
        }
Example #8
0
        static bool ExportPbrMetallicRoughness(
            UnityEngine.Material uMaterial,
            Material material,
            IGltfWritable gltf,
            ICodeLogger logger
            )
        {
            var success = true;
            var pbr     = new PbrMetallicRoughness {
                metallicFactor = 0, roughnessFactor = 1.0f
            };

            MaskMapImageExport ormImageExport = null;

            if (uMaterial.IsKeywordEnabled(k_KeywordMaskMap) && uMaterial.HasProperty(k_MaskMap))
            {
                var maskMap = uMaterial.GetTexture(k_MaskMap) as Texture2D;
                if (maskMap != null)
                {
                    ormImageExport = new MaskMapImageExport(maskMap);
                    if (AddImageExport(gltf, ormImageExport, out var ormTextureId))
                    {
                        // TODO: smartly detect if metallic roughness channels are used and not create the
                        // texture info if not.
                        pbr.metallicRoughnessTexture = new TextureInfo {
                            index = ormTextureId
                        };
                        ExportTextureTransform(pbr.metallicRoughnessTexture, uMaterial, k_MaskMap, gltf);

                        // TODO: smartly detect if occlusion channel is used and not create the
                        // texture info if not.
                        material.occlusionTexture = new OcclusionTextureInfo {
                            index = ormTextureId
                        };
                        if (uMaterial.HasProperty(k_AORemapMin))
                        {
                            var occMin = uMaterial.GetFloat(k_AORemapMin);
                            material.occlusionTexture.strength = math.clamp(1 - occMin, 0, 1);
                            var occMax = uMaterial.GetFloat(k_AORemapMax);
                            if (occMax < 1f)
                            {
                                // TODO: remap texture values
                                logger?.Warning(LogCode.RemapUnsupported, "AO");
                            }
                        }
                    }
                }
            }

            if (uMaterial.HasProperty(k_BaseColor))
            {
                pbr.baseColor = uMaterial.GetColor(k_BaseColor);
            }
            else
            if (uMaterial.HasProperty(k_Color))
            {
                pbr.baseColor = uMaterial.GetColor(k_Color);
            }

            if (uMaterial.HasProperty(k_BaseColorMap))
            {
                // TODO if additive particle, render black into alpha
                // TODO use private Material.GetFirstPropertyNameIdByAttribute here, supported from 2020.1+
                var mainTex = uMaterial.GetTexture(k_BaseColorMap);

                if (mainTex)
                {
                    if (mainTex is Texture2D)
                    {
                        pbr.baseColorTexture = ExportTextureInfo(mainTex, gltf);
                        ExportTextureTransform(pbr.baseColorTexture, uMaterial, k_BaseColorMap, gltf);
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "main", uMaterial.name);
                        success = false;
                    }
                }
            }

            if (uMaterial.HasProperty(k_Metallic))
            {
                pbr.metallicFactor = uMaterial.GetFloat(k_Metallic);
            }

            if (ormImageExport != null && uMaterial.HasProperty(k_SmoothnessRemapMax))
            {
                pbr.roughnessFactor = uMaterial.GetFloat(k_SmoothnessRemapMax);
                if (uMaterial.HasProperty(k_SmoothnessRemapMin) && uMaterial.GetFloat(k_SmoothnessRemapMin) > 0)
                {
                    logger?.Warning(LogCode.RemapUnsupported, "Smoothness");
                }
            }
            else
            if (uMaterial.HasProperty(k_Smoothness))
            {
                pbr.roughnessFactor = 1f - uMaterial.GetFloat(k_Smoothness);
            }

            material.pbrMetallicRoughness = pbr;
            return(success);
        }
        /// <summary>
        /// Converts a Unity material to a glTF material.
        /// </summary>
        /// <param name="uMaterial">Source material</param>
        /// <param name="material">Resulting material</param>
        /// <param name="gltf">Associated IGltfWriter. Is used for adding images and textures.</param>
        /// <param name="logger">Logger used for reporting</param>
        /// <returns>True if no errors occured, false otherwise</returns>
        internal static bool ConvertMaterial(UnityEngine.Material uMaterial, out Material material, IGltfWritable gltf, ICodeLogger logger)
        {
            var success = true;

            material = new Material {
                name = uMaterial.name,
                pbrMetallicRoughness = new PbrMetallicRoughness {
                    metallicFactor  = 0,
                    roughnessFactor = 1.0f
                }
            };

            switch (uMaterial.GetTag("RenderType", false, ""))
            {
            case "TransparentCutout":
                if (uMaterial.HasProperty(k_Cutoff))
                {
                    material.alphaCutoff = uMaterial.GetFloat(k_Cutoff);
                }
                material.alphaModeEnum = Material.AlphaMode.MASK;
                break;

            case "Transparent":
            case "Fade":
                material.alphaModeEnum = Material.AlphaMode.BLEND;
                break;

            default:
                material.alphaModeEnum = Material.AlphaMode.OPAQUE;
                break;
            }

            material.doubleSided = uMaterial.HasProperty(k_Cull) &&
                                   uMaterial.GetInt(k_Cull) == (int)CullMode.Off;

            if (uMaterial.IsKeywordEnabled("_EMISSION"))
            {
                if (uMaterial.HasProperty(k_EmissionColor))
                {
                    material.emissive = uMaterial.GetColor(k_EmissionColor);
                }

                if (uMaterial.HasProperty(k_EmissionMap))
                {
                    // var emissionTex = uMaterial.GetTexture(k_EmissionMap);
                    //
                    // if (emissionTex != null) {
                    //  if(emissionTex is Texture2D) {
                    //      material.emissiveTexture = ExportTextureInfo(emissionTex, TextureMapType.Emission);
                    //                        ExportTextureTransform(material.EmissiveTexture, uMaterial, "_EmissionMap");
                    //  } else {
                    //      logger?.Error(LogCode.TextureInvalidType, "emission", material.name );
                    //		success = false;
                    //  }
                    //                }
                }
            }
            if (
                uMaterial.HasProperty(k_BumpMap) &&
                (uMaterial.IsKeywordEnabled(Materials.Constants.kwNormalMap) ||
                 uMaterial.IsKeywordEnabled(k_KeywordBumpMap))
                )
            {
                var normalTex = uMaterial.GetTexture(k_BumpMap);

                if (normalTex != null)
                {
                    if (normalTex is Texture2D)
                    {
                        material.normalTexture = ExportNormalTextureInfo(normalTex, TextureMapType.Bump, uMaterial, gltf);
                        ExportTextureTransform(material.normalTexture, uMaterial, k_BumpMap, gltf);
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "normal", uMaterial.name);
                        success = false;
                    }
                }
            }

            if (uMaterial.HasProperty(k_OcclusionMap))
            {
                var occTex = uMaterial.GetTexture(k_OcclusionMap);
                if (occTex != null)
                {
                    // if(occTex is Texture2D) {
                    //  material.occlusionTexture = ExportOcclusionTextureInfo(occTex, TextureMapType.Occlusion, uMaterial);
                    //  ExportTextureTransform(material.OcclusionTexture, uMaterial, "_OcclusionMap");
                    // } else {
                    //  logger?.Error(LogCode.TextureInvalidType, "occlusion", material.name );
                    //  success = false;
                    // }
                }
            }
            if (IsUnlit(uMaterial))
            {
                ExportUnlit(material, uMaterial, gltf, logger);
            }
            else if (IsPbrMetallicRoughness(uMaterial))
            {
                success &= ExportPbrMetallicRoughness(uMaterial, out material.pbrMetallicRoughness, gltf, logger);
            }
            else if (IsPbrSpecularGlossiness(uMaterial))
            {
                // ExportPBRSpecularGlossiness(material, uMaterial);
            }
            else if (uMaterial.HasProperty(k_BaseMap))
            {
                var mainTex = uMaterial.GetTexture(k_BaseMap);
                material.pbrMetallicRoughness = new PbrMetallicRoughness {
                    baseColor = uMaterial.HasProperty(k_BaseColor)
                                                ? uMaterial.GetColor(k_BaseColor)
                                                : Color.white,
                    baseColorTexture = mainTex == null ? null : ExportTextureInfo(mainTex, TextureMapType.Main, gltf)
                };
            }
            else if (uMaterial.HasProperty(k_ColorTexture))
            {
                var mainTex = uMaterial.GetTexture(k_ColorTexture);
                material.pbrMetallicRoughness = new PbrMetallicRoughness {
                    baseColor = uMaterial.HasProperty(k_BaseColor)
                                                ? uMaterial.GetColor(k_BaseColor)
                                                : Color.white,
                    baseColorTexture = mainTex == null ? null : ExportTextureInfo(mainTex, TextureMapType.Main, gltf)
                };
            }
            else if (uMaterial.HasProperty(k_MainTex)) //else export main texture
            {
                var mainTex = uMaterial.GetTexture(k_MainTex);

                if (mainTex != null)
                {
                    material.pbrMetallicRoughness = new PbrMetallicRoughness {
                        metallicFactor   = 0, roughnessFactor = 1.0f,
                        baseColorTexture = ExportTextureInfo(mainTex, TextureMapType.Main, gltf)
                    };

                    // ExportTextureTransform(material.pbrMetallicRoughness.baseColorTexture, uMaterial, "_MainTex");
                }
                if (uMaterial.HasProperty(k_TintColor))
                {
                    //particles use _TintColor instead of _Color
                    material.pbrMetallicRoughness = material.pbrMetallicRoughness ?? new PbrMetallicRoughness {
                        metallicFactor = 0, roughnessFactor = 1.0f
                    };

                    material.pbrMetallicRoughness.baseColor = uMaterial.GetColor(k_TintColor);
                }
                material.doubleSided = true;
            }
            return(success);
        }
        static void ExportTextureTransform(TextureInfo def, UnityEngine.Material mat, int texPropertyId, IGltfWritable gltf)
        {
            var offset = mat.GetTextureOffset(texPropertyId);
            var scale  = mat.GetTextureScale(texPropertyId);

            // Counter measure for Unity/glTF texture coordinate difference
            // TODO: Offer UV conversion as alternative
            offset.y = 1 - offset.x;
            scale.y *= -1;

            if (offset != Vector2.zero || scale != Vector2.one)
            {
                gltf.RegisterExtensionUsage(Extension.TextureTransform);
                def.extensions = def.extensions ?? new TextureInfoExtension();
                def.extensions.KHR_texture_transform = new TextureTransform {
                    scale  = new[] { scale.x, scale.y },
                    offset = new[] { offset.x, offset.y }
                };
            }
        }
        static TextureInfo ExportTextureInfo(UnityEngine.Texture texture, TextureMapType textureMapType, IGltfWritable gltf)
        {
            var imageId = gltf.AddImage(texture);

            if (imageId < 0)
            {
                return(null);
            }
            var textureId = gltf.AddTexture(imageId);
            var info      = new TextureInfo {
                index = textureId,
                // texCoord = 0 // TODO: figure out which UV set was used
            };

            return(info);
        }
        static bool ExportPbrMetallicRoughness(UnityEngine.Material material, out PbrMetallicRoughness pbr, IGltfWritable gltf, ICodeLogger logger)
        {
            var success = true;

            pbr = new PbrMetallicRoughness {
                metallicFactor = 0, roughnessFactor = 1.0f
            };

            if (material.HasProperty(k_BaseColor))
            {
                pbr.baseColor = material.GetColor(k_BaseColor);
            }
            else
            if (material.HasProperty(k_Color))
            {
                pbr.baseColor = material.GetColor(k_Color);
            }

            if (material.HasProperty(k_TintColor))
            {
                //particles use _TintColor instead of _Color
                float white = 1;
                if (material.HasProperty(k_Color))
                {
                    var c = material.GetColor(k_Color);
                    white = (c.r + c.g + c.b) / 3.0f; //multiply alpha by overall whiteness of TintColor
                }

                pbr.baseColor = material.GetColor(k_TintColor) * white;
            }

            if (material.HasProperty(k_MainTex) || material.HasProperty("_BaseMap"))
            {
                // TODO if additive particle, render black into alpha
                // TODO use private Material.GetFirstPropertyNameIdByAttribute here, supported from 2020.1+
                var mainTexProperty = material.HasProperty(k_BaseMap) ? k_BaseMap : k_MainTex;
                var mainTex         = material.GetTexture(mainTexProperty);

                if (mainTex)
                {
                    if (mainTex is Texture2D)
                    {
                        pbr.baseColorTexture = ExportTextureInfo(mainTex, TextureMapType.Main, gltf);
                        ExportTextureTransform(pbr.baseColorTexture, material, mainTexProperty, gltf);
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "main", material.name);
                        success = false;
                    }
                }
            }

            if (material.HasProperty(k_Metallic) && !material.IsKeywordEnabled("_METALLICGLOSSMAP"))
            {
                pbr.metallicFactor = material.GetFloat(k_Metallic);
            }

            if (material.HasProperty(k_Glossiness) || material.HasProperty(k_Smoothness))
            {
                var   smoothnessPropertyName = material.HasProperty(k_Smoothness) ?  k_Smoothness : k_Glossiness;
                var   metallicGlossMap       = material.GetTexture(k_MetallicGlossMap);
                float smoothness             = material.GetFloat(smoothnessPropertyName);
                // legacy workaround: the UnityGLTF shaders misuse k_Glossiness as roughness but don't have a keyword for it.
                if (material.shader.name.Equals("GLTF/PbrMetallicRoughness", StringComparison.Ordinal))
                {
                    smoothness = 1 - smoothness;
                }
                pbr.roughnessFactor = (metallicGlossMap != null && material.HasProperty(k_GlossMapScale))
                                        ? material.GetFloat(k_GlossMapScale)
                                        : 1f - smoothness;
            }

            if (material.HasProperty(k_MetallicGlossMap))
            {
                var mrTex = material.GetTexture(k_MetallicGlossMap);

                if (mrTex != null)
                {
                    if (mrTex is Texture2D)
                    {
                        // pbr.metallicRoughnessTexture = ExportTextureInfo(mrTex, TextureMapType.MetallicGloss);
                        // if (material.IsKeywordEnabled("_METALLICGLOSSMAP"))
                        //  pbr.metallicFactor = 1.0f;
                        // ExportTextureTransform(pbr.MetallicRoughnessTexture, material, k_MetallicGlossMap);
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "metallic/gloss", material.name);
                        success = false;
                    }
                }
            }

            return(success);
        }
Example #13
0
 /// <summary>
 /// Converts a Unity material into a glTF material
 /// </summary>
 /// <param name="uMaterial">Source material</param>
 /// <param name="material">Resulting glTF material</param>
 /// <param name="gltf">glTF to export material to. Will be used to add required texture images</param>
 /// <param name="logger">Custom logger</param>
 /// <returns>True if material was converted successfully, false otherwise</returns>
 public abstract bool ConvertMaterial(UnityEngine.Material uMaterial, out Material material, IGltfWritable gltf, ICodeLogger logger);
        /// <summary>
        /// Converts a Unity material to a glTF material.
        /// </summary>
        /// <param name="uMaterial">Source material</param>
        /// <param name="material">Resulting material</param>
        /// <param name="gltf">Associated IGltfWriter. Is used for adding images and textures.</param>
        /// <param name="logger">Logger used for reporting</param>
        /// <returns>True if no errors occured, false otherwise</returns>
        public override bool ConvertMaterial(UnityEngine.Material uMaterial, out Material material, IGltfWritable gltf, ICodeLogger logger)
        {
            var success = true;

            material = new Material {
                name = uMaterial.name,
                pbrMetallicRoughness = new PbrMetallicRoughness {
                    metallicFactor  = 0,
                    roughnessFactor = 1.0f
                }
            };

            SetAlphaModeAndCutoff(uMaterial, material);
            material.doubleSided = IsDoubleSided(uMaterial);

            if (uMaterial.IsKeywordEnabled(k_KeywordEmission))
            {
                if (uMaterial.HasProperty(k_EmissionColor))
                {
                    var emissionColor = uMaterial.GetColor(k_EmissionColor);

                    // Clamp emissionColor to 0..1
                    var maxFactor = math.max(emissionColor.r, math.max(emissionColor.g, emissionColor.b));
                    if (maxFactor > 1f)
                    {
                        emissionColor.r /= maxFactor;
                        emissionColor.g /= maxFactor;
                        emissionColor.b /= maxFactor;
                        // TODO: use maxFactor as emissiveStrength (KHR_materials_emissive_strength)
                    }

                    material.emissive = emissionColor;
                }

                if (uMaterial.HasProperty(k_EmissionMap))
                {
                    var emissionTex = uMaterial.GetTexture(k_EmissionMap);

                    if (emissionTex != null)
                    {
                        if (emissionTex is Texture2D)
                        {
                            material.emissiveTexture = ExportTextureInfo(emissionTex, gltf);
                            if (material.emissiveTexture != null)
                            {
                                ExportTextureTransform(material.emissiveTexture, uMaterial, k_EmissionMap, gltf);
                            }
                        }
                        else
                        {
                            logger?.Error(LogCode.TextureInvalidType, "emission", material.name);
                            success = false;
                        }
                    }
                }
            }
            if (
                uMaterial.HasProperty(k_BumpMap) &&
                (uMaterial.IsKeywordEnabled(Materials.Constants.kwNormalMap) ||
                 uMaterial.IsKeywordEnabled(k_KeywordBumpMap))
                )
            {
                var normalTex = uMaterial.GetTexture(k_BumpMap);

                if (normalTex != null)
                {
                    if (normalTex is Texture2D)
                    {
                        material.normalTexture = ExportNormalTextureInfo(normalTex, uMaterial, gltf);
                        if (material.normalTexture != null)
                        {
                            ExportTextureTransform(material.normalTexture, uMaterial, k_BumpMap, gltf);
                        }
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "normal", uMaterial.name);
                        success = false;
                    }
                }
            }

            var isPbrMetallicRoughness = IsPbrMetallicRoughness(uMaterial);
            var needsMetalRoughTexture =
                isPbrMetallicRoughness &&
                (
                    HasMetallicGlossMap(uMaterial) ||
                    uMaterial.IsKeywordEnabled(k_KeywordSmoothnessTextureAlbedoChannelA)
                );

            OrmImageExport ormImageExport  = null;
            var            mainTexProperty = k_MainTex;

            if (uMaterial.HasProperty(k_BaseMap))
            {
                mainTexProperty = k_BaseMap;
            }
            else if (uMaterial.HasProperty(k_ColorTexture))
            {
                mainTexProperty = k_ColorTexture;
            }

            if (needsMetalRoughTexture)
            {
                ormImageExport = new OrmImageExport();
            }

            if (IsUnlit(uMaterial))
            {
                ExportUnlit(material, uMaterial, mainTexProperty, gltf, logger);
            }
            else if (isPbrMetallicRoughness)
            {
                success &= ExportPbrMetallicRoughness(
                    uMaterial,
                    material,
                    mainTexProperty,
                    ormImageExport,
                    gltf,
                    logger
                    );
            }
            else if (uMaterial.HasProperty(mainTexProperty))
            {
                var mainTex = uMaterial.GetTexture(mainTexProperty);
                material.pbrMetallicRoughness = new PbrMetallicRoughness {
                    metallicFactor  = 0,
                    roughnessFactor = 1.0f,
                    baseColor       = uMaterial.HasProperty(k_BaseColor)
                        ? uMaterial.GetColor(k_BaseColor)
                        : Color.white
                };
                if (mainTex != null)
                {
                    material.pbrMetallicRoughness.baseColorTexture = ExportTextureInfo(mainTex, gltf);
                    if (material.pbrMetallicRoughness.baseColorTexture != null)
                    {
                        ExportTextureTransform(material.pbrMetallicRoughness.baseColorTexture, uMaterial, mainTexProperty, gltf);
                    }
                }
                if (uMaterial.HasProperty(k_TintColor))
                {
                    //particles use _TintColor instead of _Color
                    material.pbrMetallicRoughness.baseColor = uMaterial.GetColor(k_TintColor);
                }
            }

            if (uMaterial.HasProperty(k_OcclusionMap))
            {
                var occTex = uMaterial.GetTexture(k_OcclusionMap);
                if (occTex != null)
                {
                    if (occTex is Texture2D occTex2d)
                    {
                        if (ormImageExport == null)
                        {
                            material.occlusionTexture = ExportOcclusionTextureInfo(occTex2d, uMaterial, gltf);
                        }
                        else
                        {
                            material.occlusionTexture = new OcclusionTextureInfo();
                            ormImageExport.SetOcclusionTexture(occTex2d);
                        }
                        if (material.occlusionTexture != null)
                        {
                            ExportTextureTransform(
                                material.occlusionTexture,
                                uMaterial,
                                mainTexProperty, // Standard and Lit re-use main texture transform
                                gltf
                                );
                        }
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "occlusion", material.name);
                        success = false;
                    }
                }
            }

            if (ormImageExport != null && material.pbrMetallicRoughness != null)
            {
                if (AddImageExport(gltf, ormImageExport, out var ormTextureId))
                {
                    if (material.pbrMetallicRoughness.metallicRoughnessTexture != null)
                    {
                        material.pbrMetallicRoughness.metallicRoughnessTexture.index = ormTextureId;
                        ExportTextureTransform(material.pbrMetallicRoughness.metallicRoughnessTexture, uMaterial, k_MetallicGlossMap, gltf);
                    }

                    if (ormImageExport.hasOcclusion)
                    {
                        material.occlusionTexture.index = ormTextureId;
                    }
                }
#if UNITY_IMAGECONVERSION
                else
                {
                    logger?.Error(LogCode.ExportImageFailed);
                }
#endif
            }

            if (material.occlusionTexture != null)
            {
                if (uMaterial.HasProperty(MaterialGenerator.occlusionStrengthPropId))
                {
                    material.occlusionTexture.strength = uMaterial.GetFloat(MaterialGenerator.occlusionStrengthPropId);
                }
            }

            return(success);
        }
        static bool ExportPbrMetallicRoughness(
            UnityEngine.Material uMaterial,
            Material material,
            int mainTexProperty,
            OrmImageExport ormImageExport,
            IGltfWritable gltf,
            ICodeLogger logger
            )
        {
            var success = true;
            var pbr     = new PbrMetallicRoughness {
                metallicFactor = 0, roughnessFactor = 1.0f
            };

            var hasAlphaSmoothness = uMaterial.IsKeywordEnabled(k_KeywordSmoothnessTextureAlbedoChannelA);

            if (uMaterial.HasProperty(k_BaseColor))
            {
                pbr.baseColor = uMaterial.GetColor(k_BaseColor);
            }
            else
            if (uMaterial.HasProperty(k_Color))
            {
                pbr.baseColor = uMaterial.GetColor(k_Color);
            }

            if (uMaterial.HasProperty(k_TintColor))
            {
                //particles use _TintColor instead of _Color
                float white = 1;
                if (uMaterial.HasProperty(k_Color))
                {
                    var c = uMaterial.GetColor(k_Color);
                    white = (c.r + c.g + c.b) / 3.0f; //multiply alpha by overall whiteness of TintColor
                }

                pbr.baseColor = uMaterial.GetColor(k_TintColor) * white;
            }

            if (uMaterial.HasProperty(mainTexProperty))
            {
                // TODO if additive particle, render black into alpha
                // TODO use private Material.GetFirstPropertyNameIdByAttribute here, supported from 2020.1+
                var mainTex = uMaterial.GetTexture(mainTexProperty);

                if (mainTex)
                {
                    if (mainTex is Texture2D)
                    {
                        pbr.baseColorTexture = ExportTextureInfo(
                            mainTex,
                            gltf,
                            // Force RGB for the baseColor, so that the alpha (which is smoothness)
                            // is not used for alpha-opacity
                            hasAlphaSmoothness
                                ? ImageExportBase.Format.Jpg
                                : ImageExportBase.Format.Unknown
                            );
                        if (pbr.baseColorTexture != null)
                        {
                            ExportTextureTransform(pbr.baseColorTexture, uMaterial, mainTexProperty, gltf);
                        }
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "main", uMaterial.name);
                        success = false;
                    }
                }
            }

            if (uMaterial.HasProperty(k_Metallic) && !HasMetallicGlossMap(uMaterial))
            {
                pbr.metallicFactor = uMaterial.GetFloat(k_Metallic);
            }

            if (uMaterial.HasProperty(k_Glossiness) || uMaterial.HasProperty(k_Smoothness))
            {
                var smoothnessPropId = uMaterial.HasProperty(k_Smoothness) ?  k_Smoothness : k_Glossiness;
                var metallicGlossMap = uMaterial.HasProperty(k_MetallicGlossMap) ? uMaterial.GetTexture(k_MetallicGlossMap) : null;
                var smoothness       = uMaterial.GetFloat(smoothnessPropId);
                pbr.roughnessFactor = (metallicGlossMap != null || hasAlphaSmoothness) && uMaterial.HasProperty(k_GlossMapScale)
                    ? uMaterial.GetFloat(k_GlossMapScale)
                    : 1f - smoothness;
            }

            if (uMaterial.HasProperty(k_MetallicGlossMap))
            {
                var mrTex = uMaterial.GetTexture(k_MetallicGlossMap);
                if (mrTex != null)
                {
                    if (mrTex is Texture2D mrTex2d)
                    {
                        pbr.metallicRoughnessTexture = pbr.metallicRoughnessTexture ?? new TextureInfo();
                        ormImageExport.SetMetalGlossTexture(mrTex2d);
                        if (HasMetallicGlossMap(uMaterial))
                        {
                            pbr.metallicFactor = 1.0f;
                        }
                        ExportTextureTransform(pbr.metallicRoughnessTexture, uMaterial, k_MetallicGlossMap, gltf);
                    }
                    else
                    {
                        logger?.Error(LogCode.TextureInvalidType, "metallic/gloss", uMaterial.name);
                        success = false;
                    }
                }
            }

            if (uMaterial.IsKeywordEnabled(k_KeywordSmoothnessTextureAlbedoChannelA))
            {
                var smoothnessTex = uMaterial.GetTexture(mainTexProperty) as Texture2D;
                if (smoothnessTex != null)
                {
                    pbr.metallicRoughnessTexture = pbr.metallicRoughnessTexture ?? new TextureInfo();
                    ormImageExport.SetSmoothnessTexture(smoothnessTex);
                    ExportTextureTransform(pbr.metallicRoughnessTexture, uMaterial, mainTexProperty, gltf);
                }
            }

            material.pbrMetallicRoughness = pbr;
            return(success);
        }