using System; using System.Collections.Generic; using LibMMD.Material; using UnityEngine; using UnityEngine.Rendering; namespace LibMMD.Unity3D { [Flags] public enum MmdMaterialSettings { None = 0, ReceiveShadows = 1 << 0, CastShadows = 1 << 1, Outline = 1 << 2, TextureAlphaScan = 1 << 3, All = ReceiveShadows | CastShadows | Outline | TextureAlphaScan, } /// /// Optional adapter metadata used by applications to build a shader-specific settings UI. /// Kept separate from IMmdMaterialAdapter so existing third-party adapters remain compatible. /// public interface IMmdMaterialSettingsProvider { MmdMaterialSettings SupportedSettings { get; } } public static class MmdMaterialAdapterIds { public const string Mmd = "mmd"; public const string Lit = "lit"; // Legacy IDs kept for loading existing project/user settings. public const string Standard = "standard"; public const string UrpLit = "urp-lit"; public const string LilToon = "liltoon"; public const string Custom = "custom"; } public sealed class MmdMaterialContext { public MmdUnityConfig Config; public Texture MainTexture; public Texture ToonTexture; public Texture SphereTexture; public MmdMaterial.SubTextureTypeEnum SphereTextureType; public bool IsTransparent; public bool IsTransparentOverlay; public bool EnableOutline; public bool CastShadows; public bool ReceiveShadows; public bool EnableSelfShadow; } public interface IMmdMaterialAdapter { string Id { get; } string DisplayName { get; } Shader ResolveShader(MmdMaterial source, MmdMaterialContext context); void Apply(UnityEngine.Material target, MmdMaterial source, MmdMaterialContext context); } public interface IMmdMaterialAdapterRegistry { IEnumerable Adapters { get; } IMmdMaterialAdapter Get(string id); void Register(IMmdMaterialAdapter adapter); bool Unregister(string id); } public sealed class MmdMaterialAdapterRegistry : IMmdMaterialAdapterRegistry { private readonly Dictionary _adapters = new Dictionary(StringComparer.OrdinalIgnoreCase); public static MmdMaterialAdapterRegistry Default { get; } = CreateDefault(); public IEnumerable Adapters => _adapters.Values; private static MmdMaterialAdapterRegistry CreateDefault() { var registry = new MmdMaterialAdapterRegistry(); registry.Register(new MmdBuiltInMaterialAdapter()); registry.Register(new LitMmdMaterialAdapter()); registry.Register(new CustomMmdMaterialAdapter()); return registry; } public IMmdMaterialAdapter Get(string id) { if (string.IsNullOrWhiteSpace(id)) id = MmdMaterialAdapterIds.Mmd; if (string.Equals(id, MmdMaterialAdapterIds.Standard, StringComparison.OrdinalIgnoreCase) || string.Equals(id, MmdMaterialAdapterIds.UrpLit, StringComparison.OrdinalIgnoreCase)) id = MmdMaterialAdapterIds.Lit; IMmdMaterialAdapter adapter; return _adapters.TryGetValue(id, out adapter) ? adapter : null; } public void Register(IMmdMaterialAdapter adapter) { if (adapter == null) throw new ArgumentNullException(nameof(adapter)); if (string.IsNullOrWhiteSpace(adapter.Id)) throw new ArgumentException("Adapter ID is required.", nameof(adapter)); _adapters[adapter.Id] = adapter; } public bool Unregister(string id) => !string.IsNullOrWhiteSpace(id) && _adapters.Remove(id); } public abstract class MmdMaterialAdapterBase : IMmdMaterialAdapter, IMmdMaterialSettingsProvider { public abstract string Id { get; } public abstract string DisplayName { get; } public virtual MmdMaterialSettings SupportedSettings => MmdMaterialSettings.All; public abstract Shader ResolveShader(MmdMaterial source, MmdMaterialContext context); public virtual void Apply(UnityEngine.Material target, MmdMaterial source, MmdMaterialContext context) { SetColor(target, "_Color", source.DiffuseColor); SetTexture(target, "_MainTex", context.MainTexture); SetColor(target, "_SpecColor", source.SpecularColor); SetFloat(target, "_OutlineWidth", source.EdgeSize); SetColor(target, "_OutlineColor", source.EdgeColor); } protected static Shader FindFirst(params string[] shaderNames) { foreach (var shaderName in shaderNames) { if (string.IsNullOrWhiteSpace(shaderName)) continue; var shader = Shader.Find(shaderName); if (shader != null) return shader; } return null; } protected static void SetColor(UnityEngine.Material material, string name, Color value) { if (material.HasProperty(name)) material.SetColor(name, value); } protected static void SetFloat(UnityEngine.Material material, string name, float value) { if (material.HasProperty(name)) material.SetFloat(name, value); } protected static void SetTexture(UnityEngine.Material material, string name, Texture value) { if (value == null || !material.HasProperty(name)) return; material.SetTexture(name, value); material.SetTextureScale(name, Vector2.one); } protected static void SetKeyword(UnityEngine.Material material, string keyword, bool enabled) { if (enabled) material.EnableKeyword(keyword); else material.DisableKeyword(keyword); } protected static void ConfigureBlend(UnityEngine.Material material, bool transparent, string transparentKeyword) { SetFloat(material, "_SrcBlend", transparent ? (float)BlendMode.SrcAlpha : (float)BlendMode.One); SetFloat(material, "_DstBlend", transparent ? (float)BlendMode.OneMinusSrcAlpha : (float)BlendMode.Zero); SetFloat(material, "_ZWrite", transparent ? 0.0f : 1.0f); if (!string.IsNullOrEmpty(transparentKeyword)) SetKeyword(material, transparentKeyword, transparent); material.renderQueue = transparent ? (int)RenderQueue.Transparent : -1; } } }