diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapDecoder.shader b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapDecoder.shader deleted file mode 100644 index 76b76f285..000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapDecoder.shader +++ /dev/null @@ -1,54 +0,0 @@ -Shader "UniGLTF/NormalMapDecoder" -{ - Properties - { - _MainTex ("Texture", 2D) = "white" {} - } - 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; - - fixed4 frag (v2f i) : SV_Target - { - half4 col = tex2D(_MainTex, i.uv); - - col.xyz = (UnpackNormal(col) + 1) * 0.5; - col.w = 1; - - return col; - } - ENDCG - } - } -} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapExporter.shader b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapExporter.shader new file mode 100644 index 000000000..4480b321e --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapExporter.shader @@ -0,0 +1,55 @@ +Shader "Hidden/UniGLTF/NormalMapExporter" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + 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; + + fixed4 frag (v2f i) : SV_Target + { + half4 col = tex2D(_MainTex, i.uv); + + // Convert from compressed normal value to usual normal value. + col.xyz = (UnpackNormal(col) + 1) * 0.5; + col.w = 1; + + return col; + } + ENDCG + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapDecoder.shader.meta b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapExporter.shader.meta similarity index 100% rename from Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapDecoder.shader.meta rename to Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/NormalMapExporter.shader.meta 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..f42507579 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader @@ -0,0 +1,70 @@ +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 metallicRoughnessTex = tex2D(_GltfMetallicRoughnessTexture, i.uv); + half4 occlusionTex = tex2D(_GltfOcclusionTexture, i.uv); + + half occlusion = occlusionTex.r; // R: glTF Occlusion + half roughness = metallicRoughnessTex.g * _GltfRoughnessFactor; // G: glTF Roughness + half metallic = metallicRoughnessTex.b * _GltfMetallicFactor; // B: glTF Metallic + + 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/StandardVColor.shader.meta b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader.meta similarity index 58% rename from Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardVColor.shader.meta rename to Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader.meta index 2efb7376e..a3de647a4 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardVColor.shader.meta +++ b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardMapImporter.shader.meta @@ -1,7 +1,7 @@ fileFormatVersion: 2 -guid: 5ef7bdb14a8f23043805e41692d10787 -timeCreated: 1528269709 -licenseType: Pro +guid: fa5d94522a5d93442a7515698d7ab799 +timeCreated: 1533558728 +licenseType: Free ShaderImporter: defaultTextures: [] userData: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardVColor.shader b/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardVColor.shader deleted file mode 100644 index 2cf04f963..000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/Resources/Shaders/StandardVColor.shader +++ /dev/null @@ -1,56 +0,0 @@ -// Upgrade NOTE: upgraded instancing buffer 'Props' to new syntax. - -Shader "UniGLTF/StandardVColor" { - Properties { - _Color ("Color", Color) = (1,1,1,1) - _MainTex ("Albedo (RGB)", 2D) = "white" {} - _Glossiness ("Smoothness", Range(0,1)) = 0.5 - _Metallic ("Metallic", Range(0,1)) = 0.0 - } - SubShader { - Tags { "RenderType"="Opaque" } - LOD 200 - - CGPROGRAM - // Physically based Standard lighting model, and enable shadows on all light types - #pragma surface surf Standard fullforwardshadows vertex:vert - - // Use shader model 3.0 target, to get nicer looking lighting - #pragma target 3.0 - - sampler2D _MainTex; - - struct Input { - float2 uv_MainTex; - float4 v_Color; - }; - - half _Glossiness; - half _Metallic; - fixed4 _Color; - - // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. - // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. - // #pragma instancing_options assumeuniformscaling - UNITY_INSTANCING_BUFFER_START(Props) - // put more per-instance properties here - UNITY_INSTANCING_BUFFER_END(Props) - - void vert(inout appdata_full v, out Input o){ - UNITY_INITIALIZE_OUTPUT(Input, o); - o.v_Color = v.color; - } - - void surf (Input IN, inout SurfaceOutputStandard o) { - // Albedo comes from a texture tinted by color - fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; - o.Albedo = c.rgb * IN.v_Color.rgb; - // Metallic and smoothness come from slider variables - o.Metallic = _Metallic; - o.Smoothness = _Glossiness; - o.Alpha = c.a; - } - ENDCG - } - FallBack "Diffuse" -} diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/NormalConverter.cs b/Assets/VRMShaders/GLTF/IO/Runtime/NormalConverter.cs index d87b40ff4..ebb7589c6 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/NormalConverter.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/NormalConverter.cs @@ -4,23 +4,23 @@ namespace VRMShaders { public static class NormalConverter { - private static Material m_decoder; - private static Material Decoder + private static Material _exporter; + private static Material Exporter { get { - if (m_decoder == null) + if (_exporter == null) { - m_decoder = new Material(Shader.Find("UniGLTF/NormalMapDecoder")); + _exporter = new Material(Shader.Find("Hidden/UniGLTF/NormalMapExporter")); } - return m_decoder; + return _exporter; } } // Unity texture to GLTF data public static Texture2D Export(Texture texture) { - return TextureConverter.CopyTexture(texture, ColorSpace.Linear, false, Decoder); + return TextureConverter.CopyTexture(texture, ColorSpace.Linear, false, Exporter); } } } diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/OcclusionMetallicRoughnessConverter.cs b/Assets/VRMShaders/GLTF/IO/Runtime/OcclusionMetallicRoughnessConverter.cs index 3d4635081..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; } @@ -146,7 +111,7 @@ namespace VRMShaders } else if (occlusionTexture) { - var dst = TextureConverter.CreateEmptyTextureWithSettings(metallicSmoothTexture, ColorSpace.Linear, false); + var dst = TextureConverter.CreateEmptyTextureWithSettings(occlusionTexture, ColorSpace.Linear, false); var linearOcclusion = TextureConverter.CopyTexture(occlusionTexture, ColorSpace.Linear, false, null); dst.SetPixels32(linearOcclusion.GetPixels32().Select(x => ExportPixel(default, smoothness, x)).ToArray()); dst.Apply(); diff --git a/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs b/Assets/VRMShaders/GLTF/IO/Tests/MetallicRoughnessConverterTests.cs index 7c90a8943..4199cbd5c 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,46 +75,56 @@ namespace VRMShaders { var roughnessFactor = 1.0f; Assert.That( - OcclusionMetallicRoughnessConverter.ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), - // r <- 255 : Same metallic (src.r) - // g <- 0 : (Unused) + ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), + // r <- 255 : metallic (metallicRoughness.b * metallicFactor) + // g <- 0 : occlusion (occlusion.r) // b <- 0 : (Unused) - // a <- 0 : ((1 - sqrt(src.g(as float) * roughnessFactor)))(as uint8) + // a <- 0 : smoothness (1.0 - (metallicRoughness.g * roughnessFactor)) Is.EqualTo(new Color32(255, 0, 0, 0))); } { var roughnessFactor = 1.0f; Assert.That( - OcclusionMetallicRoughnessConverter.ImportPixel(new Color32(255, 128, 255, 255), 1.0f, roughnessFactor, default), - // r <- 255 : Same metallic (src.r) - // g <- 0 : (Unused) + ImportPixel(new Color32(255, 127, 255, 255), 1.0f, roughnessFactor, default), + // r <- 255 : metallic (metallicRoughness.b * metallicFactor) + // g <- 0 : occlusion (occlusion.r) // b <- 0 : (Unused) - // a <- 128 : ((1 - sqrt(src.g(as float) * roughnessFactor)))(as uint8) - Is.EqualTo(new Color32(255, 0, 0, 127))); // smoothness 0.5 * src.a 1.0 + // a <- 128 : smoothness (1.0 - (metallicRoughness.g * roughnessFactor)) + Is.EqualTo(new Color32(255, 0, 0, 128))); // A:smoothness = 1.0 - (0.5 * 1.0) = 0.5 } { var roughnessFactor = 0.5f; Assert.That( - OcclusionMetallicRoughnessConverter.ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), - // r <- 255 : Same metallic (src.r) - // g <- 0 : (Unused) + ImportPixel(new Color32(255, 127, 255, 255), 1.0f, roughnessFactor, default), + // r <- 255 : metallic (metallicRoughness.b * metallicFactor) + // g <- 0 : occlusion (occlusion.r) // b <- 0 : (Unused) - // a <- 74 : ((1 - sqrt(src.g(as float) * roughnessFactor)))(as uint8) - Is.EqualTo(new Color32(255, 0, 0, 127))); + // a <- 191 : smoothness (1.0 - (metallicRoughness.g * roughnessFactor)) + Is.EqualTo(new Color32(255, 0, 0, 191))); // A:smoothness = 1.0 - (0.5 * 0.5) = 0.75 } { var roughnessFactor = 0.0f; Assert.That( - OcclusionMetallicRoughnessConverter.ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), - // r <- 255 : Same metallic (src.r) - // g <- 0 : (Unused) + ImportPixel(new Color32(255, 255, 255, 255), 1.0f, roughnessFactor, default), + // r <- 255 : metallic (metallicRoughness.b * metallicFactor) + // g <- 0 : occlusion (occlusion.r) // b <- 0 : (Unused) - // a <- 255 : ((1 - sqrt(src.g(as float) * roughnessFactor)))(as uint8) + // a <- 255 : smoothness (1.0 - (metallicRoughness.g * roughnessFactor)) Is.EqualTo(new Color32(255, 0, 0, 255))); } + + { + Assert.That( + ImportPixel(new Color32(222, 200, 100, 255), 0.5f, 0.25f, new Color32(127, 0, 0, 0)), + // r <- 50 : metallic (metallicRoughness.b * metallicFactor) + // g <- 127 : occlusion (occlusion.r) + // b <- 0 : (Unused) + // a <- 205 : smoothness (1.0 - (metallicRoughness.g * roughnessFactor)) + Is.EqualTo(new Color32(50, 127, 0, 205))); + } } [Test]