using System; using UnityEngine; using UnityEngine.Rendering; using VRMShaders.VRM10.MToon10.Runtime; namespace VRMShaders.VRM10.MToon10.Runtime { public sealed class MToonValidator { private readonly Material _material; public MToonValidator(Material material) { _material = material; } public void Validate() { var alphaMode = (MToon10AlphaMode) _material.GetInt(MToon10Prop.AlphaMode); var zWriteMode = (MToon10TransparentWithZWriteMode) _material.GetInt(MToon10Prop.TransparentWithZWrite); var renderQueueOffset = _material.GetInt(MToon10Prop.RenderQueueOffsetNumber); var doubleSidedMode = (MToon10DoubleSidedMode) _material.GetInt(MToon10Prop.DoubleSided); SetUnityShaderPassSettings(_material, alphaMode, zWriteMode, renderQueueOffset, doubleSidedMode); SetUnityShaderVariants(_material); } private static void SetUnityShaderPassSettings(Material material, MToon10AlphaMode alphaMode, MToon10TransparentWithZWriteMode zWriteMode, int renderQueueOffset, MToon10DoubleSidedMode doubleSidedMode) { material.SetInt(MToon10Prop.AlphaMode, (int) alphaMode); material.SetInt(MToon10Prop.TransparentWithZWrite, (int) zWriteMode); material.SetInt(MToon10Prop.DoubleSided, (int) doubleSidedMode); switch (alphaMode) { case MToon10AlphaMode.Opaque: material.SetOverrideTag(UnityRenderTag.Key, UnityRenderTag.OpaqueValue); material.SetInt(MToon10Prop.UnitySrcBlend, (int) BlendMode.One); material.SetInt(MToon10Prop.UnityDstBlend, (int) BlendMode.Zero); material.SetInt(MToon10Prop.UnityZWrite, (int) UnityZWriteMode.On); material.SetInt(MToon10Prop.UnityAlphaToMask, (int) UnityAlphaToMaskMode.Off); renderQueueOffset = 0; material.renderQueue = (int) RenderQueue.Geometry; break; case MToon10AlphaMode.Cutout: material.SetOverrideTag(UnityRenderTag.Key, UnityRenderTag.TransparentCutoutValue); material.SetInt(MToon10Prop.UnitySrcBlend, (int) BlendMode.One); material.SetInt(MToon10Prop.UnityDstBlend, (int) BlendMode.Zero); material.SetInt(MToon10Prop.UnityZWrite, (int) UnityZWriteMode.On); material.SetInt(MToon10Prop.UnityAlphaToMask, (int) UnityAlphaToMaskMode.On); renderQueueOffset = 0; material.renderQueue = (int) RenderQueue.AlphaTest; break; case MToon10AlphaMode.Transparent when zWriteMode == MToon10TransparentWithZWriteMode.Off: material.SetOverrideTag(UnityRenderTag.Key, UnityRenderTag.TransparentValue); material.SetInt(MToon10Prop.UnitySrcBlend, (int) BlendMode.SrcAlpha); material.SetInt(MToon10Prop.UnityDstBlend, (int) BlendMode.OneMinusSrcAlpha); material.SetInt(MToon10Prop.UnityZWrite, (int) UnityZWriteMode.Off); material.SetInt(MToon10Prop.UnityAlphaToMask, (int) UnityAlphaToMaskMode.Off); renderQueueOffset = Mathf.Clamp(renderQueueOffset, -9, 0); material.renderQueue = (int) RenderQueue.Transparent + renderQueueOffset; break; case MToon10AlphaMode.Transparent when zWriteMode == MToon10TransparentWithZWriteMode.On: material.SetOverrideTag(UnityRenderTag.Key, UnityRenderTag.TransparentValue); material.SetInt(MToon10Prop.UnitySrcBlend, (int) BlendMode.SrcAlpha); material.SetInt(MToon10Prop.UnityDstBlend, (int) BlendMode.OneMinusSrcAlpha); material.SetInt(MToon10Prop.UnityZWrite, (int) UnityZWriteMode.On); material.SetInt(MToon10Prop.UnityAlphaToMask, (int) UnityAlphaToMaskMode.Off); renderQueueOffset = Mathf.Clamp(renderQueueOffset, 0, +9); material.renderQueue = (int) RenderQueue.GeometryLast + 1 + renderQueueOffset; // Transparent First + N break; default: throw new ArgumentOutOfRangeException(nameof(alphaMode), alphaMode, null); } switch (doubleSidedMode) { case MToon10DoubleSidedMode.Off: material.SetInt(MToon10Prop.UnityCullMode, (int) UnityCullMode.Back); break; case MToon10DoubleSidedMode.On: material.SetInt(MToon10Prop.UnityCullMode, (int) UnityCullMode.Off); break; default: throw new ArgumentOutOfRangeException(nameof(doubleSidedMode), doubleSidedMode, null); } // Set after validation material.SetInt(MToon10Prop.RenderQueueOffsetNumber, renderQueueOffset); } private static void SetUnityCullingSettings(Material material, MToon10DoubleSidedMode doubleSidedMode) { } private static void SetUnityShaderVariants(Material material) { material.SetKeyword( UnityAlphaModeKeyword.AlphaTest, (MToon10AlphaMode) material.GetInt(MToon10Prop.AlphaMode) == MToon10AlphaMode.Cutout ); material.SetKeyword( UnityAlphaModeKeyword.AlphaBlend, (MToon10AlphaMode) material.GetInt(MToon10Prop.AlphaMode) == MToon10AlphaMode.Transparent ); material.SetKeyword( UnityAlphaModeKeyword.AlphaPremultiply, false ); material.SetKeyword( MToon10NormalMapKeyword.On, material.GetTexture(MToon10Prop.NormalTexture) != null ); material.SetKeyword( MToon10EmissiveMapKeyword.On, material.GetTexture(MToon10Prop.EmissiveTexture) != null ); material.SetKeyword( MToon10RimMapKeyword.On, material.GetTexture(MToon10Prop.MatcapTexture) != null || // Matcap material.GetTexture(MToon10Prop.RimMultiplyTexture) != null // Rim ); material.SetKeyword( MToon10ParameterMapKeyword.On, material.GetTexture(MToon10Prop.ShadingShiftTexture) != null || // Shading Shift (R) material.GetTexture(MToon10Prop.OutlineWidthMultiplyTexture) != null || // Outline Width (G) material.GetTexture(MToon10Prop.UvAnimationMaskTexture) != null // UV Anim Mask (B) ); material.SetKeyword( MToon10OutlineModeKeyword.World, (MToon10OutlineMode) material.GetInt(MToon10Prop.OutlineWidthMode) == MToon10OutlineMode.World ); material.SetKeyword( MToon10OutlineModeKeyword.Screen, (MToon10OutlineMode) material.GetInt(MToon10Prop.OutlineWidthMode) == MToon10OutlineMode.Screen ); } } }