using System; using System.Linq; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace UniGLTF { public interface ITextureConverter { Texture2D GetImportTexture(Texture2D texture); Texture2D GetExportTexture(Texture2D texture); } public static class TextureConverter { public delegate Color32 ColorConversion(Color32 color); public static Texture2D Convert(Texture2D texture, glTFTextureTypes textureType, ColorConversion colorConversion, Material convertMaterial) { var copyTexture = TextureItem.CopyTexture(texture, TextureIO.GetColorSpace(textureType), convertMaterial); if (colorConversion != null) { copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => colorConversion(x)).ToArray()); copyTexture.Apply(); } copyTexture.name = texture.name; return copyTexture; } public static void AppendTextureExtension(Texture texture, string extension) { if (!texture.name.EndsWith(extension)) { texture.name = texture.name + extension; } } public static void RemoveTextureExtension(Texture texture, string extension) { if (texture.name.EndsWith(extension)) { texture.name = texture.name.Replace(extension, ""); } } } public class MetallicRoughnessConverter : ITextureConverter { private const string m_extension = ".metallicRoughness"; private float _smoothnessOrRoughness; public MetallicRoughnessConverter(float smoothnessOrRoughness) { _smoothnessOrRoughness = smoothnessOrRoughness; } public Texture2D GetImportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Metallic, Import, null); TextureConverter.AppendTextureExtension(converted, m_extension); return converted; } public Texture2D GetExportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Metallic, Export, null); TextureConverter.RemoveTextureExtension(converted, m_extension); return converted; } public Color32 Import(Color32 src) { // Roughness(glTF): dst.g -> Smoothness(Unity): src.a (with conversion) // Metallic(glTF) : dst.b -> Metallic(Unity) : src.r var pixelRoughnessFactor = (src.g * _smoothnessOrRoughness) / 255.0f; // roughness var pixelSmoothness = 1.0f - Mathf.Sqrt(pixelRoughnessFactor); return new Color32 { r = src.b, g = 0, b = 0, // Bake roughness values into a texture. // See: https://github.com/dwango/UniVRM/issues/212. a = (byte)Mathf.Clamp(pixelSmoothness * 255, 0, 255), }; } public Color32 Export(Color32 src) { // Smoothness(Unity): src.a -> Roughness(glTF): dst.g (with conversion) // Metallic(Unity) : src.r -> Metallic(glTF) : dst.b var pixelSmoothness = (src.a * _smoothnessOrRoughness) / 255.0f; // smoothness // https://blogs.unity3d.com/jp/2016/01/25/ggx-in-unity-5-3/ var pixelRoughnessFactorSqrt = (1.0f - pixelSmoothness); var pixelRoughnessFactor = pixelRoughnessFactorSqrt * pixelRoughnessFactorSqrt; return new Color32 { r = 0, // Bake smoothness values into a texture. // See: https://github.com/dwango/UniVRM/issues/212. g = (byte)Mathf.Clamp(pixelRoughnessFactor * 255, 0, 255), b = src.r, a = 255, }; } } public class NormalConverter : ITextureConverter { private const string m_extension = ".normal"; private Material m_decoder; private Material GetDecoder() { if (m_decoder == null) { m_decoder = new Material(Shader.Find("UniGLTF/NormalMapDecoder")); } return m_decoder; } private Material m_encoder; private Material GetEncoder() { if (m_encoder == null) { m_encoder = new Material(Shader.Find("UniGLTF/NormalMapEncoder")); } return m_encoder; } // GLTF data to Unity texture // ConvertToNormalValueFromRawColorWhenCompressionIsRequired public Texture2D GetImportTexture(Texture2D texture) { var mat = GetEncoder(); var converted = TextureConverter.Convert(texture, glTFTextureTypes.Normal, null, mat); TextureConverter.AppendTextureExtension(converted, m_extension); return converted; } // Unity texture to GLTF data // ConvertToRawColorWhenNormalValueIsCompressed public Texture2D GetExportTexture(Texture2D texture) { var mat = GetDecoder(); var converted = TextureConverter.Convert(texture, glTFTextureTypes.Normal, null, mat); TextureConverter.RemoveTextureExtension(converted, m_extension); return converted; } } public class OcclusionConverter : ITextureConverter { private const string m_extension = ".occlusion"; public Texture2D GetImportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Occlusion, Import, null); TextureConverter.AppendTextureExtension(converted, m_extension); return converted; } public Texture2D GetExportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Occlusion, Export, null); TextureConverter.RemoveTextureExtension(converted, m_extension); return converted; } public Color32 Import(Color32 src) { return new Color32 { r = 0, g = src.r, b = 0, a = 255, }; } public Color32 Export(Color32 src) { return new Color32 { r = src.g, g = 0, b = 0, a = 255, }; } } }