diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader new file mode 100644 index 000000000..3115bd222 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader @@ -0,0 +1,68 @@ +Shader "Hidden/UniGLTF/StandardMapImporter" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + _GltfMetallicFactor ("glTF Metallic Factor", Float) = 0.0 + _GltfRoughnessFactor ("glTF Roughness Factor", Float) = 0.0 + _GltfMetallicRoughnessTexture ("glTF Metallic Roughness Texture", 2D) = "black" {} + _GltfOcclusionTexture ("glTF Occlusion Texture", 2D) = "black" {} + } + SubShader + { + // No culling or depth + Cull Off ZWrite Off ZTest Always + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = v.uv; + return o; + } + + sampler2D _MainTex; + half _GltfMetallicFactor; + half _GltfRoughnessFactor; + sampler2D _GltfMetallicRoughnessTexture; + sampler2D _GltfOcclusionTexture; + + fixed4 frag (v2f i) : SV_Target + { + half4 metallicRoughness = tex2D(_GltfMetallicRoughnessTexture, i.uv); + half metallic = metallicRoughness.b * _GltfMetallicFactor; + half roughness = metallicRoughness.g * _GltfRoughnessFactor; + half occlusion = tex2D(_GltfOcclusionTexture, i.uv).r; + + fixed4 result; + result.r = metallic; // R: Unity Metallic + result.g = occlusion; // G: Unity Occlusion + result.b = 0; // B: Unity Heightmap (no use) + result.a = 1.0 - roughness; // A: Unity Smoothness + + return result; + } + ENDCG + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader.meta b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader.meta new file mode 100644 index 000000000..a3de647a4 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: fa5d94522a5d93442a7515698d7ab799 +timeCreated: 1533558728 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/OcclusionMetallicRoughnessConverter.cs b/Assets/VRMShaders/GLTF/IO/Runtime/OcclusionMetallicRoughnessConverter.cs index 539500883..72d4e8e8f 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/OcclusionMetallicRoughnessConverter.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/OcclusionMetallicRoughnessConverter.cs @@ -21,77 +21,42 @@ namespace VRMShaders /// public static class OcclusionMetallicRoughnessConverter { - public static Texture2D Import(Texture2D metallicRoughnessTexture, - float metallicFactor, float roughnessFactor, Texture2D occlusionTexture) + private static Material exporter; + private static Material Exporter { - // TODO: Replace with Shader implementation - if (metallicRoughnessTexture != null && occlusionTexture != null) + get { - if (metallicRoughnessTexture == occlusionTexture) + if (exporter == null) { - var copyMetallicRoughness = TextureConverter.CopyTexture(metallicRoughnessTexture, ColorSpace.Linear, true, null); - var metallicRoughnessPixels = copyMetallicRoughness.GetPixels32(); - for (int i = 0; i < metallicRoughnessPixels.Length; ++i) - { - metallicRoughnessPixels[i] = ImportPixel(metallicRoughnessPixels[i], metallicFactor, roughnessFactor, metallicRoughnessPixels[i]); - } - copyMetallicRoughness.SetPixels32(metallicRoughnessPixels); - copyMetallicRoughness.Apply(); - copyMetallicRoughness.name = metallicRoughnessTexture.name; - return copyMetallicRoughness; + exporter = new Material(Shader.Find("Hidden/UniGLTF/StandardMapImporter")); } - else - { - var copyMetallicRoughness = TextureConverter.CopyTexture(metallicRoughnessTexture, ColorSpace.Linear, true, null); - var metallicRoughnessPixels = copyMetallicRoughness.GetPixels32(); - var copyOcclusion = TextureConverter.CopyTexture(occlusionTexture, ColorSpace.Linear, false, null); - var occlusionPixels = copyOcclusion.GetPixels32(); - if (metallicRoughnessPixels.Length != occlusionPixels.Length) - { - throw new NotImplementedException(); - } - for (int i = 0; i < metallicRoughnessPixels.Length; ++i) - { - metallicRoughnessPixels[i] = ImportPixel(metallicRoughnessPixels[i], metallicFactor, roughnessFactor, occlusionPixels[i]); - } - copyMetallicRoughness.SetPixels32(metallicRoughnessPixels); - copyMetallicRoughness.Apply(); - copyMetallicRoughness.name = metallicRoughnessTexture.name; - DestroyTexture(copyOcclusion); - return copyMetallicRoughness; - } - } - else if (metallicRoughnessTexture != null) - { - var copyTexture = TextureConverter.CopyTexture(metallicRoughnessTexture, ColorSpace.Linear, true, null); - copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => ImportPixel(x, metallicFactor, roughnessFactor, default)).ToArray()); - copyTexture.Apply(); - copyTexture.name = metallicRoughnessTexture.name; - return copyTexture; - } - else if (occlusionTexture != null) - { - var copyTexture = TextureConverter.CopyTexture(occlusionTexture, ColorSpace.Linear, true, null); - copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => ImportPixel(default, metallicFactor, roughnessFactor, x)).ToArray()); - copyTexture.Apply(); - copyTexture.name = occlusionTexture.name; - return copyTexture; - } - else - { - throw new ArgumentNullException("no texture"); + return exporter; } } - public static Color32 ImportPixel(Color32 metallicRoughness, float metallicFactor, float roughnessFactor, Color32 occlusion) + public static Texture2D Import(Texture2D metallicRoughnessTexture, + float metallicFactor, float roughnessFactor, Texture2D occlusionTexture) { - var dst = new Color32 + if (metallicRoughnessTexture == null && occlusionTexture == null) { - r = (byte)(metallicRoughness.b * metallicFactor), // Metallic - g = occlusion.r, // Occlusion - b = 0, // not used - a = (byte)(255 - metallicRoughness.g * roughnessFactor), // Roughness to Smoothness - }; + throw new ArgumentNullException("no texture"); + } + + var src = metallicRoughnessTexture != null ? metallicRoughnessTexture : occlusionTexture; + + Exporter.mainTexture = src; + Exporter.SetTexture("_GltfMetallicRoughnessTexture", metallicRoughnessTexture); + Exporter.SetTexture("_GltfOcclusionTexture", occlusionTexture); + Exporter.SetFloat("_GltfMetallicFactor", metallicFactor); + Exporter.SetFloat("_GltfRoughnessFactor", roughnessFactor); + + var dst = TextureConverter.CopyTexture(src, ColorSpace.Linear, true, Exporter); + + Exporter.mainTexture = null; + Exporter.SetTexture("_GltfMetallicRoughnessTexture", null); + Exporter.SetTexture("_GltfOcclusionTexture", null); + Exporter.SetFloat("_GltfMetallicFactor", 0); + Exporter.SetFloat("_GltfRoughnessFactor", 0); return dst; } diff --git a/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs b/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs index 7c90a8943..e44377f01 100644 --- a/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs +++ b/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs @@ -1,3 +1,4 @@ +using System.Linq; using NUnit.Framework; using UnityEngine; @@ -5,6 +6,32 @@ namespace VRMShaders { public class MetallicRoughnessConverterTests { + private Color32 ImportPixel(Color32 metallicRoughnessPixel, float metallicFactor, float roughnessFactor, Color32 occlusionPixel) + { + var metallicRoughnessTexture = new Texture2D(4, 4, TextureFormat.ARGB32, mipChain: false, linear: true); + metallicRoughnessTexture.SetPixels32(Enumerable.Range(0, 16).Select(_ => metallicRoughnessPixel).ToArray()); + metallicRoughnessTexture.Apply(); + + var occlusionTexture = new Texture2D(4, 4, TextureFormat.ARGB32, mipChain: false, linear: true); + occlusionTexture.SetPixels32(Enumerable.Range(0, 16).Select(_ => occlusionPixel).ToArray()); + occlusionTexture.Apply(); + + var converted = OcclusionMetallicRoughnessConverter.Import( + metallicRoughnessTexture, + metallicFactor, + roughnessFactor, + occlusionTexture + ); + + var result = converted.GetPixels32()[0]; + + UnityEngine.Object.DestroyImmediate(metallicRoughnessTexture); + UnityEngine.Object.DestroyImmediate(occlusionTexture); + UnityEngine.Object.DestroyImmediate(converted); + + return result; + } + [Test] public void ExportingColorTest() { @@ -48,7 +75,7 @@ namespace VRMShaders { var roughnessFactor = 1.0f; Assert.That( - OcclusionMetallicRoughnessConverter.ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), + ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), // r <- 255 : Same metallic (src.r) // g <- 0 : (Unused) // b <- 0 : (Unused) @@ -59,7 +86,7 @@ namespace VRMShaders { var roughnessFactor = 1.0f; Assert.That( - OcclusionMetallicRoughnessConverter.ImportPixel(new Color32(255, 128, 255, 255), 1.0f, roughnessFactor, default), + ImportPixel(new Color32(255, 128, 255, 255), 1.0f, roughnessFactor, default), // r <- 255 : Same metallic (src.r) // g <- 0 : (Unused) // b <- 0 : (Unused) @@ -70,7 +97,7 @@ namespace VRMShaders { var roughnessFactor = 0.5f; Assert.That( - OcclusionMetallicRoughnessConverter.ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), + ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), // r <- 255 : Same metallic (src.r) // g <- 0 : (Unused) // b <- 0 : (Unused) @@ -81,7 +108,7 @@ namespace VRMShaders { var roughnessFactor = 0.0f; Assert.That( - OcclusionMetallicRoughnessConverter.ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), + ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), // r <- 255 : Same metallic (src.r) // g <- 0 : (Unused) // b <- 0 : (Unused)