From 165278bd227648701decde9e7d89266ae156173f Mon Sep 17 00:00:00 2001 From: mob-sakai <12690315+mob-sakai@users.noreply.github.com> Date: Thu, 14 Nov 2024 17:04:08 +0900 Subject: [PATCH] feat: MaskingShape components always use stencil mask close #203, close #209 --- .../src/Runtime/MaskingShape/MaskingShape.cs | 15 ++++++++++--- .../MaskingShape/TerminalMaskingShape.cs | 2 +- .../UISoftMaskProjectSettings.cs | 12 +--------- Packages/src/Runtime/SoftMaskable.cs | 22 +++++++++++++++---- .../src/Runtime/Utilities/SoftMaskUtils.cs | 2 -- Packages/src/Runtime/Utilities/Utils.cs | 22 +++++++++---------- 6 files changed, 42 insertions(+), 33 deletions(-) diff --git a/Packages/src/Runtime/MaskingShape/MaskingShape.cs b/Packages/src/Runtime/MaskingShape/MaskingShape.cs index 8c0dbfd..5251339 100644 --- a/Packages/src/Runtime/MaskingShape/MaskingShape.cs +++ b/Packages/src/Runtime/MaskingShape/MaskingShape.cs @@ -280,15 +280,19 @@ Material IMaterialModifier.GetModifiedMaterial(Material baseMaterial) var colorMask = m_ShowMaskGraphic ? ColorWriteMask.All : 0; { Profiler.BeginSample("(SM4UI)[MaskingShape)] GetModifiedMaterial > StencilMaterial.Add"); + var writeMask = Utils.GetHighestBit(_stencilBits); + var readMask = _stencilBits & ~writeMask; switch (maskingMethod) { case MaskingMethod.Additive: maskMat = StencilMaterial.Add(baseMaterial, _stencilBits, StencilOp.Replace, - CompareFunction.NotEqual, colorMask, _stencilBits, _stencilBits); + CompareFunction.Equal, colorMask, readMask, writeMask); break; case MaskingMethod.Subtract: - maskMat = StencilMaterial.Add(baseMaterial, _stencilBits, StencilOp.Invert, - CompareFunction.Equal, colorMask, _stencilBits, _stencilBits); + var op = SoftMaskEnabled() ? StencilOp.Keep : StencilOp.Zero; + var comp = writeMask == 1 ? CompareFunction.Always : CompareFunction.Equal; + maskMat = StencilMaterial.Add(baseMaterial, _stencilBits, op, + comp, colorMask, readMask, writeMask); break; } @@ -331,6 +335,11 @@ internal bool AntiAliasingEnabled() return isActiveAndEnabled && _mask is SoftMask softMask && softMask.AntiAliasingEnabled(); } + internal bool SoftMaskEnabled() + { + return isActiveAndEnabled && _mask is SoftMask softMask && softMask.SoftMaskingEnabled(); + } + private void RecalculateStencilIfNeeded() { if (!isActiveAndEnabled) diff --git a/Packages/src/Runtime/MaskingShape/TerminalMaskingShape.cs b/Packages/src/Runtime/MaskingShape/TerminalMaskingShape.cs index 2e516cb..bc0ca05 100644 --- a/Packages/src/Runtime/MaskingShape/TerminalMaskingShape.cs +++ b/Packages/src/Runtime/MaskingShape/TerminalMaskingShape.cs @@ -102,7 +102,7 @@ public override Material GetModifiedMaterial(Material baseMaterial) } var maskMat = StencilMaterial.Add(baseMaterial, _stencilBits, StencilOp.Zero, CompareFunction.Equal, 0, - _stencilBits, _stencilBits); + _stencilBits, Utils.GetHighestBit(_stencilBits)); StencilMaterial.Remove(m_MaskMaterial); m_MaskMaterial = maskMat; diff --git a/Packages/src/Runtime/ProjectSettings/UISoftMaskProjectSettings.cs b/Packages/src/Runtime/ProjectSettings/UISoftMaskProjectSettings.cs index 31d39ad..5ffd312 100644 --- a/Packages/src/Runtime/ProjectSettings/UISoftMaskProjectSettings.cs +++ b/Packages/src/Runtime/ProjectSettings/UISoftMaskProjectSettings.cs @@ -27,11 +27,6 @@ public class UISoftMaskProjectSettings : PreloadedProjectSettings instance.m_SoftMaskEnabled; - public static bool useStencilOutsideScreen => -#if UNITY_EDITOR - instance.m_UseStencilOutsideScreen; -#else - false; -#endif + public static bool useStencilOutsideScreen => true; #if UNITY_MODULE_VR public static bool stereoEnabled => diff --git a/Packages/src/Runtime/SoftMaskable.cs b/Packages/src/Runtime/SoftMaskable.cs index fae819c..69402a5 100755 --- a/Packages/src/Runtime/SoftMaskable.cs +++ b/Packages/src/Runtime/SoftMaskable.cs @@ -112,6 +112,7 @@ public float power private MaskableGraphic _graphic; private Material _maskableMaterial; private bool _shouldRecalculateStencil; + private Mask _mask; private SoftMask _softMask; private int _softMaskDepth; private int _stencilBits; @@ -147,6 +148,7 @@ private void OnDisable() } _graphic = null; + _mask = null; _softMask = null; MaterialRepository.Release(ref _maskableMaterial); @@ -160,6 +162,7 @@ private void OnDestroy() { _graphic = null; _maskableMaterial = null; + _mask = null; _softMask = null; _checkGraphic = null; @@ -199,14 +202,25 @@ Material IMaterialModifier.GetModifiedMaterial(Material baseMaterial) } RecalculateStencilIfNeeded(); - _softMaskDepth = _softMask ? _softMask.softMaskDepth : -1; - - if (!_softMask || _softMaskDepth < 0 || 4 <= _softMaskDepth) + var softMaskDepth = _softMask ? _softMask.softMaskDepth : -1; + if (softMaskDepth < 0 || 4 <= softMaskDepth) { + _softMaskDepth = -1; MaterialRepository.Release(ref _maskableMaterial); return baseMaterial; } + _softMaskDepth = softMaskDepth; + if (0 <= _softMaskDepth + && _softMask == _mask + && _softMask.SoftMaskingEnabled() + && TryGetComponent(out var shape) + && shape.isActiveAndEnabled + && shape.maskingMethod == MaskingShape.MaskingMethod.Subtract) + { + _softMaskDepth -= 1; + } + Profiler.BeginSample("(SM4UI)[SoftMaskable] GetModifiedMaterial"); var isStereo = UISoftMaskProjectSettings.stereoEnabled && _graphic.canvas.IsStereoCanvas(); var useStencil = UISoftMaskProjectSettings.useStencilOutsideScreen; @@ -263,7 +277,7 @@ private void RecalculateStencilIfNeeded() if (!_shouldRecalculateStencil) return; _shouldRecalculateStencil = false; var useStencil = UISoftMaskProjectSettings.useStencilOutsideScreen; - _stencilBits = Utils.GetStencilBits(transform, false, useStencil, out var _, out _softMask); + _stencilBits = Utils.GetStencilBits(transform, false, useStencil, out _mask, out _softMask); } private void CheckGraphic() diff --git a/Packages/src/Runtime/Utilities/SoftMaskUtils.cs b/Packages/src/Runtime/Utilities/SoftMaskUtils.cs index f7ec05b..07654e2 100644 --- a/Packages/src/Runtime/Utilities/SoftMaskUtils.cs +++ b/Packages/src/Runtime/Utilities/SoftMaskUtils.cs @@ -45,7 +45,6 @@ internal static class SoftMaskUtils private static readonly int s_MainTex = Shader.PropertyToID("_MainTex"); private static readonly int s_ColorMask = Shader.PropertyToID("_ColorMask"); private static readonly int s_BlendOp = Shader.PropertyToID("_BlendOp"); - private static readonly int s_StencilReadMask = Shader.PropertyToID("_StencilReadMask"); private static readonly int s_ThresholdMin = Shader.PropertyToID("_ThresholdMin"); private static readonly int s_ThresholdMax = Shader.PropertyToID("_ThresholdMax"); private static readonly int s_RenderScale = Shader.PropertyToID("_RenderScale"); @@ -203,7 +202,6 @@ public static Material CreateSoftMaskable( mat.SetTexture(s_SoftMaskTex, softMaskBuffer); mat.SetInt(s_SoftMaskableStereo, isStereo ? 1 : 0); mat.SetInt(s_SoftMaskableEnable, 1); - mat.SetInt(s_StencilReadMask, stencilBits); mat.SetVector(s_SoftMaskColor, new Vector4( 0 <= softMaskDepth ? 1 : 0, 1 <= softMaskDepth ? 1 : 0, diff --git a/Packages/src/Runtime/Utilities/Utils.cs b/Packages/src/Runtime/Utilities/Utils.cs index 6e16d38..84c96eb 100644 --- a/Packages/src/Runtime/Utilities/Utils.cs +++ b/Packages/src/Runtime/Utilities/Utils.cs @@ -64,13 +64,6 @@ public static int GetStencilBits(Transform transform, bool includeSelf, bool use if (!nearestMask) { nearestMask = mask; - if (FrameCache.TryGet(nearestMask, nameof(GetStencilBits), out stencilBits)) - { - FrameCache.TryGet(nearestMask, nameof(GetStencilBits), out nearestSoftMask); - - Profiler.EndSample(); - return stencilBits; - } } stencilBits = 0 < depth++ ? stencilBits << 1 : 0; @@ -98,11 +91,6 @@ public static int GetStencilBits(Transform transform, bool includeSelf, bool use stencilBits = Mathf.Min(stencilBits, 255); Profiler.EndSample(); - if (nearestMask) - { - FrameCache.Set(nearestMask, nameof(GetStencilBits), stencilBits); - FrameCache.Set(nearestMask, nameof(GetStencilBits), nearestSoftMask); - } return stencilBits; } @@ -181,6 +169,16 @@ private static bool AlphaHitTestValid(RawImage src, Vector2 sp, Camera eventCame } } + public static int GetHighestBit(int i) + { + i |= i >> 1; + i |= i >> 2; + i |= i >> 4; + i |= i >> 8; + // i |= (i >> 16); + return i - (i >> 1); + } + #if UNITY_EDITOR private static string GetWarningMessage(Graphic src) {