diff --git a/Assets/VRM/UniGLTF/Editor/Tests/TextureTests.cs b/Assets/VRM/UniGLTF/Editor/Tests/TextureTests.cs index 4237f9156..e56302191 100644 --- a/Assets/VRM/UniGLTF/Editor/Tests/TextureTests.cs +++ b/Assets/VRM/UniGLTF/Editor/Tests/TextureTests.cs @@ -31,4 +31,99 @@ namespace UniGLTF Assert.AreEqual(glFilter.LINEAR_MIPMAP_LINEAR, sampler.magFilter); } } + + public class MetallicRoughnessConverterTests + { + [Test] + public void ExportingColorTest() + { + { + var smoothness = 1.0f; + var conv = new MetallicRoughnessConverter(smoothness); + Assert.That( + conv.Export(new Color32(255, 255, 255, 255)), + // r <- 0 : (Unused) + // g <- 0 : ((1 - s.a(as float) * smoothness) ^ 2)(as int8) + // b <- 255 : Same metallic (src.r) + // a <- 255 : (Unused) + Is.EqualTo(new Color32(0, 0, 255, 255))); + } + + { + var smoothness = 0.5f; + var conv = new MetallicRoughnessConverter(smoothness); + Assert.That( + conv.Export(new Color32(255, 255, 255, 255)), + // r <- 0 : (Unused) + // g <- 63 : ((1 - s.a(as float) * smoothness) ^ 2)(as int8) + // b <- 255 : Same metallic (src.r) + // a <- 255 : (Unused) + Is.EqualTo(new Color32(0, 63, 255, 255))); + } + + { + var smoothness = 0.0f; + var conv = new MetallicRoughnessConverter(smoothness); + Assert.That( + conv.Export(new Color32(255, 255, 255, 255)), + // r <- 0 : (Unused) + // g <- 255 : ((1 - s.a(as float) * smoothness) ^ 2)(as int8) + // b <- 255 : Same metallic (src.r) + // a <- 255 : (Unused) + Is.EqualTo(new Color32(0, 255, 255, 255))); + } + } + + [Test] + public void ImportingColorTest() + { + { + var roughnessFactor = 1.0f; + var conv = new MetallicRoughnessConverter(roughnessFactor); + Assert.That( + conv.Import(new Color32(255, 255, 255, 255)), + // r <- 255 : Same metallic (src.r) + // g <- 0 : (Unused) + // b <- 0 : (Unused) + // a <- 255 : ((1 - sqrt(s.g(as float) * roughnessFactor)))(as int8) + Is.EqualTo(new Color32(255, 0, 0, 0))); + } + + { + var roughnessFactor = 1.0f; + var conv = new MetallicRoughnessConverter(roughnessFactor); + Assert.That( + conv.Import(new Color32(255, 63, 255, 255)), + // r <- 255 : Same metallic (src.r) + // g <- 0 : (Unused) + // b <- 0 : (Unused) + // a <- 255 : ((1 - sqrt(s.g(as float) * roughnessFactor)))(as int8) + Is.EqualTo(new Color32(255, 0, 0, 128))); // smoothness 0.5 * src.a 1.0 + } + + { + var roughnessFactor = 0.5f; + var conv = new MetallicRoughnessConverter(roughnessFactor); + Assert.That( + conv.Import(new Color32(255, 255, 255, 255)), + // r <- 255 : Same metallic (src.r) + // g <- 0 : (Unused) + // b <- 0 : (Unused) + // a <- 255 : ((1 - sqrt(s.g(as float) * roughnessFactor)))(as int8) + Is.EqualTo(new Color32(255, 0, 0, 74))); + } + + { + var roughnessFactor = 0.0f; + var conv = new MetallicRoughnessConverter(roughnessFactor); + Assert.That( + conv.Import(new Color32(255, 255, 255, 255)), + // r <- 255 : Same metallic (src.r) + // g <- 0 : (Unused) + // b <- 0 : (Unused) + // a <- 255 : ((1 - sqrt(s.g(as float) * roughnessFactor)))(as int8) + Is.EqualTo(new Color32(255, 0, 0, 255))); + } + } + } } diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs index 613971d76..e8943e336 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs @@ -61,20 +61,30 @@ namespace UniGLTF int index = -1; if (m.HasProperty("_MetallicGlossMap")) { - index = textureManager.ConvertAndGetIndex(m.GetTexture("_MetallicGlossMap"), new MetallicRoughnessConverter()); + float smoothness = 0.0f; + if (m.HasProperty("_GlossMapScale")) + { + smoothness = m.GetFloat("_GlossMapScale"); + } + + // Bake smoothness values into a texture. + var converter = new MetallicRoughnessConverter(smoothness); + index = textureManager.ConvertAndGetIndex(m.GetTexture("_MetallicGlossMap"), converter); if (index != -1) { - material.pbrMetallicRoughness.metallicRoughnessTexture = new glTFMaterialMetallicRoughnessTextureInfo() - { - index = index, - }; + material.pbrMetallicRoughness.metallicRoughnessTexture = + new glTFMaterialMetallicRoughnessTextureInfo() + { + index = index, + }; } } - if (index != -1 && m.HasProperty("_GlossMapScale")) + if (index != -1) { material.pbrMetallicRoughness.metallicFactor = 1.0f; - material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_GlossMapScale"); + // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. + material.pbrMetallicRoughness.roughnessFactor = 1.0f; } else { @@ -82,11 +92,11 @@ namespace UniGLTF { material.pbrMetallicRoughness.metallicFactor = m.GetFloat("_Metallic"); } + if (m.HasProperty("_Glossiness")) { material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_Glossiness"); } - } } diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs index 335b32397..31db25670 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs @@ -164,11 +164,13 @@ namespace UniGLTF if (texture != null) { var prop = "_MetallicGlossMap"; - material.SetTexture(prop, texture.ConvertTexture(prop)); + // Bake roughnessFactor values into a texture. + material.SetTexture(prop, texture.ConvertTexture(prop, x.pbrMetallicRoughness.roughnessFactor)); } material.SetFloat("_Metallic", 1.0f); - material.SetFloat("_GlossMapScale", 1.0f - x.pbrMetallicRoughness.roughnessFactor); + // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. + material.SetFloat("_GlossMapScale", 1.0f); } else { diff --git a/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs b/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs index b10e27682..d6323588a 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using UnityEngine; #if UNITY_EDITOR @@ -46,10 +47,17 @@ namespace UniGLTF } } - class MetallicRoughnessConverter : ITextureConverter + 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); @@ -66,28 +74,46 @@ namespace UniGLTF 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, - a = (byte)(255 - src.g), + // 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, - g = (byte)(255 - src.a), + // 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, }; } } - class NormalConverter : ITextureConverter + public class NormalConverter : ITextureConverter { private const string m_extension = ".normal"; @@ -132,7 +158,7 @@ namespace UniGLTF } } - class OcclusionConverter : ITextureConverter + public class OcclusionConverter : ITextureConverter { private const string m_extension = ".occlusion"; diff --git a/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs b/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs index 1f79ca13f..87f7fb26a 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs @@ -30,7 +30,13 @@ namespace UniGLTF get { return m_converts; } } - public Texture2D ConvertTexture(string prop) + /// + /// + /// + /// + /// used only when converting MetallicRoughness maps + /// + public Texture2D ConvertTexture(string prop, float smoothnessOrRoughness = 1.0f) { var convertedTexture = Converts.FirstOrDefault(x => x.Key == prop); if (convertedTexture.Value != null) @@ -63,7 +69,7 @@ namespace UniGLTF if (prop == "_MetallicGlossMap") { - var converted = new MetallicRoughnessConverter().GetImportTexture(Texture); + var converted = new MetallicRoughnessConverter(smoothnessOrRoughness).GetImportTexture(Texture); m_converts.Add(prop, converted); return converted; }