From c95753fc8e9cb6a0201563b26ec65052cdcc53ec Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 14 Mar 2019 22:26:52 +0900 Subject: [PATCH 1/5] Bake smoothness and roughnessFactor into textures. Treat smoothness and roughnessFactor as hardcoded-value 1.0 in Unity world (Resolve #212) --- .../UniGLTF/Scripts/IO/MaterialExporter.cs | 31 +++++++++++++------ .../UniGLTF/Scripts/IO/MaterialImporter.cs | 7 +++-- .../UniGLTF/Scripts/IO/TextureConverter.cs | 20 ++++++++++-- Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs | 10 ++++-- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs index 613971d76..34570b527 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs @@ -61,33 +61,44 @@ 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 - { + else { if (m.HasProperty("_Metallic")) { material.pbrMetallicRoughness.metallicFactor = m.GetFloat("_Metallic"); } + if (m.HasProperty("_Glossiness")) { material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_Glossiness"); } - } + + } static void Export_Normal(Material m, TextureExportManager textureManager, glTFMaterial material) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs index 335b32397..5e37f544b 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs @@ -164,11 +164,14 @@ namespace UniGLTF if (texture != null) { var prop = "_MetallicGlossMap"; - material.SetTexture(prop, texture.ConvertTexture(prop)); + var smoothness = 1.0f - x.pbrMetallicRoughness.roughnessFactor; + // Bake smoothness values into a texture. + material.SetTexture(prop, texture.ConvertTexture(prop, smoothness)); } 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..2c96649b2 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 @@ -50,6 +51,13 @@ namespace UniGLTF { private const string m_extension = ".metallicRoughness"; + private float _smoothness; + + public MetallicRoughnessConverter(float smoothness) + { + _smoothness = smoothness; + } + public Texture2D GetImportTexture(Texture2D texture) { var converted = TextureConverter.Convert(texture, glTFTextureTypes.Metallic, Import, null); @@ -66,21 +74,29 @@ 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 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)(255 - Math.Min(src.g * (1.0f - _smoothness), 255)), }; } public Color32 Export(Color32 src) { + // Smoothness(Unity): src.a -> Roughness(glTF): dst.g (with conversion) + // Metallic(Unity) : src.r -> Metallic(glTF) : dst.b 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)(255 - Math.Min(src.a * _smoothness, 255)), b = src.r, a = 255, }; diff --git a/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs b/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs index 1f79ca13f..421a87074 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 smoothness = 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(smoothness).GetImportTexture(Texture); m_converts.Add(prop, converted); return converted; } From 92f501e8377bd6582783685dcf7d5fd6b13ff976 Mon Sep 17 00:00:00 2001 From: yutopp Date: Thu, 14 Mar 2019 22:29:57 +0900 Subject: [PATCH 2/5] Fix indents --- Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs index 34570b527..e8943e336 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MaterialExporter.cs @@ -86,7 +86,8 @@ namespace UniGLTF // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. material.pbrMetallicRoughness.roughnessFactor = 1.0f; } - else { + else + { if (m.HasProperty("_Metallic")) { material.pbrMetallicRoughness.metallicFactor = m.GetFloat("_Metallic"); @@ -97,8 +98,6 @@ namespace UniGLTF material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_Glossiness"); } } - - } static void Export_Normal(Material m, TextureExportManager textureManager, glTFMaterial material) From c8489af8ed141c6dd522087780e316d5b4972ea4 Mon Sep 17 00:00:00 2001 From: yutopp Date: Fri, 15 Mar 2019 15:38:34 +0900 Subject: [PATCH 3/5] Fix calculation of smoothness and roughnessFactor conversion --- .../UniGLTF/Scripts/IO/MaterialImporter.cs | 5 ++--- .../UniGLTF/Scripts/IO/TextureConverter.cs | 19 ++++++++++++++----- Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs | 4 ++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs index 5e37f544b..31db25670 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MaterialImporter.cs @@ -164,9 +164,8 @@ namespace UniGLTF if (texture != null) { var prop = "_MetallicGlossMap"; - var smoothness = 1.0f - x.pbrMetallicRoughness.roughnessFactor; - // Bake smoothness values into a texture. - material.SetTexture(prop, texture.ConvertTexture(prop, smoothness)); + // Bake roughnessFactor values into a texture. + material.SetTexture(prop, texture.ConvertTexture(prop, x.pbrMetallicRoughness.roughnessFactor)); } material.SetFloat("_Metallic", 1.0f); diff --git a/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs b/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs index 2c96649b2..43e0350ac 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs @@ -51,11 +51,11 @@ namespace UniGLTF { private const string m_extension = ".metallicRoughness"; - private float _smoothness; + private float _smoothnessOrRoughness; - public MetallicRoughnessConverter(float smoothness) + public MetallicRoughnessConverter(float smoothnessOrRoughness) { - _smoothness = smoothness; + _smoothnessOrRoughness = smoothnessOrRoughness; } public Texture2D GetImportTexture(Texture2D texture) @@ -76,6 +76,10 @@ namespace UniGLTF { // Roughness(glTF): dst.g -> Smoothness(Unity): src.a (with conversion) // Metallic(glTF) : dst.b -> Metallic(Unity) : src.r + + var pixelRoughnessFactor = src.g * _smoothnessOrRoughness; // roughness + var pixelSmoothness = 1.0f - Mathf.Sqrt(pixelRoughnessFactor); + return new Color32 { r = src.b, @@ -83,7 +87,7 @@ namespace UniGLTF b = 0, // Bake roughness values into a texture. // See: https://github.com/dwango/UniVRM/issues/212. - a = (byte)(255 - Math.Min(src.g * (1.0f - _smoothness), 255)), + a = (byte)Mathf.Clamp(pixelSmoothness * 255, 0, 255), }; } @@ -91,12 +95,17 @@ namespace UniGLTF { // Smoothness(Unity): src.a -> Roughness(glTF): dst.g (with conversion) // Metallic(Unity) : src.r -> Metallic(glTF) : dst.b + + var pixelSmoothness = src.a * _smoothnessOrRoughness; // smoothness + // https://blogs.unity3d.com/jp/2016/01/25/ggx-in-unity-5-3/ + var pixelRoughnessFactor = (1.0f - pixelSmoothness) * (1.0f - pixelSmoothness); + return new Color32 { r = 0, // Bake smoothness values into a texture. // See: https://github.com/dwango/UniVRM/issues/212. - g = (byte)(255 - Math.Min(src.a * _smoothness, 255)), + g = (byte)Mathf.Clamp(pixelRoughnessFactor * 255, 0, 255), b = src.r, a = 255, }; diff --git a/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs b/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs index 421a87074..87f7fb26a 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/TextureItem.cs @@ -36,7 +36,7 @@ namespace UniGLTF /// /// used only when converting MetallicRoughness maps /// - public Texture2D ConvertTexture(string prop, float smoothness = 1.0f) + public Texture2D ConvertTexture(string prop, float smoothnessOrRoughness = 1.0f) { var convertedTexture = Converts.FirstOrDefault(x => x.Key == prop); if (convertedTexture.Value != null) @@ -69,7 +69,7 @@ namespace UniGLTF if (prop == "_MetallicGlossMap") { - var converted = new MetallicRoughnessConverter(smoothness).GetImportTexture(Texture); + var converted = new MetallicRoughnessConverter(smoothnessOrRoughness).GetImportTexture(Texture); m_converts.Add(prop, converted); return converted; } From 1f4c2d080c98428cc0a7a12487f638da65dd7843 Mon Sep 17 00:00:00 2001 From: yutopp Date: Fri, 15 Mar 2019 17:05:26 +0900 Subject: [PATCH 4/5] Fix calculation. Make converters public to testing --- Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs b/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs index 43e0350ac..d6323588a 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/TextureConverter.cs @@ -47,7 +47,7 @@ namespace UniGLTF } } - class MetallicRoughnessConverter : ITextureConverter + public class MetallicRoughnessConverter : ITextureConverter { private const string m_extension = ".metallicRoughness"; @@ -77,7 +77,7 @@ namespace UniGLTF // Roughness(glTF): dst.g -> Smoothness(Unity): src.a (with conversion) // Metallic(glTF) : dst.b -> Metallic(Unity) : src.r - var pixelRoughnessFactor = src.g * _smoothnessOrRoughness; // roughness + var pixelRoughnessFactor = (src.g * _smoothnessOrRoughness) / 255.0f; // roughness var pixelSmoothness = 1.0f - Mathf.Sqrt(pixelRoughnessFactor); return new Color32 @@ -96,9 +96,10 @@ namespace UniGLTF // Smoothness(Unity): src.a -> Roughness(glTF): dst.g (with conversion) // Metallic(Unity) : src.r -> Metallic(glTF) : dst.b - var pixelSmoothness = src.a * _smoothnessOrRoughness; // smoothness + var pixelSmoothness = (src.a * _smoothnessOrRoughness) / 255.0f; // smoothness // https://blogs.unity3d.com/jp/2016/01/25/ggx-in-unity-5-3/ - var pixelRoughnessFactor = (1.0f - pixelSmoothness) * (1.0f - pixelSmoothness); + var pixelRoughnessFactorSqrt = (1.0f - pixelSmoothness); + var pixelRoughnessFactor = pixelRoughnessFactorSqrt * pixelRoughnessFactorSqrt; return new Color32 { @@ -112,7 +113,7 @@ namespace UniGLTF } } - class NormalConverter : ITextureConverter + public class NormalConverter : ITextureConverter { private const string m_extension = ".normal"; @@ -157,7 +158,7 @@ namespace UniGLTF } } - class OcclusionConverter : ITextureConverter + public class OcclusionConverter : ITextureConverter { private const string m_extension = ".occlusion"; From be5c318e9aaea6bae9701cde5fad8856ad1f182f Mon Sep 17 00:00:00 2001 From: yutopp Date: Fri, 15 Mar 2019 17:06:11 +0900 Subject: [PATCH 5/5] Add tests for MetallicRoughnessConverter --- .../VRM/UniGLTF/Editor/Tests/TextureTests.cs | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) 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))); + } + } + } }