using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; namespace LeTai.TrueShadow { public partial class ShadowRenderer { // TODO: cleanup unused mask materials static readonly Dictionary<(bool, Material), Material> MASK_MATERIALS_CACHE = new Dictionary<(bool, Material), Material>(); internal static void ClearMaskMaterialCache() { foreach (var keyValuePair in MASK_MATERIALS_CACHE) { if(Application.isPlaying) Destroy(keyValuePair.Value); else DestroyImmediate(keyValuePair.Value); } MASK_MATERIALS_CACHE.Clear(); } public Material GetModifiedMaterial(Material baseMaterial) { if (!shadow) return baseMaterial; shadow.ModifyShadowRendererMaterial(baseMaterial); if (!baseMaterial.HasProperty(ShaderId.COLOR_MASK) || !baseMaterial.HasProperty(ShaderId.STENCIL_OP)) return baseMaterial; bool casterIsMask = shadow.GetComponent() != null; MASK_MATERIALS_CACHE.TryGetValue((casterIsMask, baseMaterial), out var mat); if (!mat) { mat = new Material(baseMaterial); if (shadow.ShadowAsSibling) { // Prevent shadow from writing to stencil mask mat.SetInt(ShaderId.COLOR_MASK, (int) ColorWriteMask.All); mat.SetInt(ShaderId.STENCIL_OP, (int) StencilOp.Keep); } else if (casterIsMask) { // Escape mask if we have one var baseStencilId = mat.GetInt(ShaderId.STENCIL_ID) + 1; int stencilDepth = 0; for (; stencilDepth < 8; stencilDepth++) { if (((baseStencilId >> stencilDepth) & 1) == 1) break; } stencilDepth = Mathf.Max(0, stencilDepth - 1); var stencilId = (1 << stencilDepth) - 1; mat.SetInt(ShaderId.STENCIL_ID, stencilId); mat.SetInt(ShaderId.STENCIL_READ_MASK, stencilId); } MASK_MATERIALS_CACHE[(casterIsMask, baseMaterial)] = mat; } return mat; } } }