Files
MinFt/Client/LocalPackages/SoftMaskForUGUI-3.5.0/Runtime/MaskingShape/MaskingShape.cs
Liubing\LB 3d8d4d18f3 first commit
先修复一下,错误的场景

删除不必要的钓场资产

修复into场景

update:更新meta文件,修复报错

update:修复资源

修复第一章节建造

修复建造第三章

update:删除多余内容

update:更新README.md

update:还原图标

update:更新README

update:更新配置
2026-04-28 02:17:22 +08:00

498 lines
16 KiB
C#

using System;
using Coffee.UISoftMaskInternal;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using UnityEngine.UI;
namespace Coffee.UISoftMask
{
[ExecuteAlways]
[RequireComponent(typeof(Graphic))]
[DisallowMultipleComponent]
[Icon("Packages/com.coffee.softmask-for-ugui/Icons/SoftMaskIcon.png")]
public class MaskingShape : UIBehaviour, IMeshModifier, IMaterialModifier, IComparable<MaskingShape>, IMaskable,
ISoftMasking
{
public enum MaskingMethod
{
Additive,
Subtract
}
public enum RaycastMethod
{
Auto,
Additive,
Subtract,
Ignore
}
[Tooltip("Masking method.")]
[SerializeField]
private MaskingMethod m_MaskingMethod = MaskingMethod.Additive;
[Tooltip("Show the graphic that is associated with the Mask render area.")]
[SerializeField]
private bool m_ShowMaskGraphic;
[Tooltip("The transparent part of the mask cannot be clicked.\n" +
"This can be achieved by enabling Read/Write enabled in the Texture Import Settings for the texture.\n\n" +
"NOTE: Enable this only if necessary, as it will require more graphics memory and processing time.")]
[SerializeField]
private bool m_AlphaHitTest;
[Tooltip("The threshold for anti-alias masking.\n" +
"The smaller this value, the less jagged it is.")]
[SerializeField]
[Range(0f, 1f)]
private float m_AntiAliasingThreshold;
[Tooltip("The minimum and maximum alpha values used for soft masking.\n" +
"The larger the gap between these values, the stronger the softness effect.")]
[SerializeField]
private MinMax01 m_SoftnessRange = new MinMax01(0, 1f);
[Tooltip("Method to determine whether this masking shape should be a raycast target.")]
[SerializeField]
private RaycastMethod m_RaycastMethod = RaycastMethod.Auto;
private bool _antiAliasingRegistered;
private MaskingShapeContainer _container;
private Graphic _graphic;
private Mask _mask;
private Material _maskMaterial;
private Mesh _mesh;
private MaterialPropertyBlock _mpb;
private Matrix4x4 _prevTransformMatrix;
private UnityAction _setContainerDirty;
private bool _shouldRecalculateStencil;
private int _stencilBits;
private Action _updateAntiAliasing;
private UnityAction _updateContainer;
public Graphic graphic => _graphic || TryGetComponent(out _graphic) ? _graphic : null;
public bool hasTransformChanged =>
transform.HasChanged(ref _prevTransformMatrix, UISoftMaskProjectSettings.transformSensitivity);
/// <summary>
/// Sync parameters with SoftMask component.
/// </summary>
internal ISoftMasking parent { get; set; }
public MaskingMethod maskingMethod
{
get => parent != null ? parent.maskingMethod : m_MaskingMethod;
set
{
if (m_MaskingMethod == value) return;
m_MaskingMethod = value;
SetContainerDirty();
SetMaterialDirty();
}
}
/// <summary>
/// Show the graphic that is associated with the Mask render area.
/// </summary>
public bool showMaskGraphic
{
get => parent != null ? parent.showMaskGraphic : m_ShowMaskGraphic;
set
{
if (m_ShowMaskGraphic == value) return;
m_ShowMaskGraphic = value;
SetMaterialDirty();
}
}
/// <summary>
/// The transparent part of the mask cannot be clicked.
/// This can be achieved by enabling Read/Write enabled in the Texture Import Settings for the texture.
/// <para></para>
/// NOTE: Enable this only if necessary, as it will require more graphics memory and processing time.
/// </summary>
public bool alphaHitTest
{
get => parent != null ? parent.alphaHitTest : m_AlphaHitTest;
set => m_AlphaHitTest = value;
}
/// <summary>
/// Threshold for anti-alias masking.
/// The smaller this value, the less jagged it is.
/// </summary>
public float antiAliasingThreshold
{
get => parent != null ? parent.antiAliasingThreshold : m_AntiAliasingThreshold;
set => m_AntiAliasingThreshold = value;
}
/// <summary>
/// The minimum and maximum alpha values used for soft masking.
/// The larger the gap between these values, the stronger the softness effect.
/// </summary>
public MinMax01 softnessRange
{
get => parent != null ? parent.softnessRange : m_SoftnessRange;
set
{
if (m_SoftnessRange.Approximately(value)) return;
m_SoftnessRange = value;
SetContainerDirty();
}
}
/// <summary>
/// Method to determine whether this masking shape should be a raycast target.
/// </summary>
public RaycastMethod raycastMethod
{
get => parent != null ? parent.raycastMethod : m_RaycastMethod;
set => m_RaycastMethod = value;
}
/// <summary>
/// Method to determine whether this masking shape should be a raycast target.
/// </summary>
public RaycastMethod actualRaycastMethod
{
get
{
return raycastMethod != RaycastMethod.Auto
? raycastMethod
: maskingMethod == MaskingMethod.Additive
? RaycastMethod.Additive
: RaycastMethod.Subtract;
}
}
protected override void OnEnable()
{
UpdateContainer();
if (graphic)
{
graphic.RegisterDirtyMaterialCallback(_updateContainer ?? (_updateContainer = UpdateContainer));
graphic.RegisterDirtyVerticesCallback(_setContainerDirty ?? (_setContainerDirty = SetContainerDirty));
graphic.RegisterDirtyLayoutCallback(_setContainerDirty ?? (_setContainerDirty = SetContainerDirty));
SetMaterialDirty();
graphic.SetVerticesDirty();
}
RegisterAntiAliasingIfNeeded();
UpdateAntiAliasing();
_shouldRecalculateStencil = true;
}
protected override void OnDisable()
{
_mask = null;
StencilMaterial.Remove(_maskMaterial);
_maskMaterial = null;
MeshExtensions.Return(ref _mesh);
SoftMaskUtils.materialPropertyBlockPool.Return(ref _mpb);
SetContainerDirty();
UpdateContainer();
RegisterAntiAliasingIfNeeded();
if (graphic)
{
graphic.UnregisterDirtyMaterialCallback(_updateContainer ?? (_updateContainer = UpdateContainer));
graphic.UnregisterDirtyVerticesCallback(_setContainerDirty ?? (_setContainerDirty = SetContainerDirty));
graphic.UnregisterDirtyLayoutCallback(_setContainerDirty ?? (_setContainerDirty = SetContainerDirty));
SetMaterialDirty();
graphic.SetVerticesDirty();
}
}
protected override void OnCanvasHierarchyChanged()
{
UpdateContainer();
}
protected override void OnDidApplyAnimationProperties()
{
SetContainerDirty();
}
protected override void OnRectTransformDimensionsChange()
{
SetContainerDirty();
}
protected override void OnTransformParentChanged()
{
UpdateContainer();
}
#if UNITY_EDITOR
protected override void OnValidate()
{
SetContainerDirty();
RegisterAntiAliasingIfNeeded();
UpdateAntiAliasing();
SetMaterialDirty();
}
#endif
int IComparable<MaskingShape>.CompareTo(MaskingShape other)
{
if (this == other) return 0;
if (!this && other) return -1;
if (this && !other) return 1;
var depth = graphic ? graphic.depth : -1;
var otherDepth = other.graphic ? other.graphic.depth : -1;
if (depth != -1 && otherDepth != -1)
{
return depth - otherDepth;
}
return transform.CompareHierarchyIndex(other.transform, _container ? _container.transform : null);
}
void IMaskable.RecalculateMasking()
{
StencilMaterial.Remove(_maskMaterial);
_maskMaterial = null;
_shouldRecalculateStencil = true;
UpdateContainer();
RegisterAntiAliasingIfNeeded();
}
Material IMaterialModifier.GetModifiedMaterial(Material baseMaterial)
{
if (!isActiveAndEnabled)
{
StencilMaterial.Remove(_maskMaterial);
_maskMaterial = null;
return baseMaterial;
}
// Not in mask.
RecalculateStencilIfNeeded();
if (_stencilBits == 0 && !_mask)
{
StencilMaterial.Remove(_maskMaterial);
_maskMaterial = null;
return baseMaterial;
}
// Mask material
var toUse = baseMaterial;
Material maskMat = null;
var colorMask = m_ShowMaskGraphic && !AntiAliasingEnabled() ? 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.Equal, colorMask, readMask, writeMask);
break;
case MaskingMethod.Subtract:
var op = SoftMaskEnabled() ? StencilOp.Keep : StencilOp.Zero;
var comp = writeMask == 1 ? CompareFunction.Always : CompareFunction.Equal;
maskMat = StencilMaterial.Add(baseMaterial, _stencilBits, op,
comp, colorMask, _stencilBits, writeMask);
break;
}
Profiler.EndSample();
}
StencilMaterial.Remove(_maskMaterial);
if (maskMat && maskMat != baseMaterial)
{
toUse = _maskMaterial = maskMat;
}
return toUse;
}
void IMeshModifier.ModifyMesh(Mesh mesh)
{
if (!isActiveAndEnabled)
{
MeshExtensions.Return(ref _mesh);
return;
}
mesh.CopyTo(_mesh ? _mesh : _mesh = MeshExtensions.Rent());
}
void IMeshModifier.ModifyMesh(VertexHelper verts)
{
if (!isActiveAndEnabled)
{
MeshExtensions.Return(ref _mesh);
return;
}
verts.CopyTo(_mesh ? _mesh : _mesh = MeshExtensions.Rent());
}
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)
{
_mask = null;
_stencilBits = 0;
return;
}
if (!_shouldRecalculateStencil) return;
_shouldRecalculateStencil = false;
var useStencil = UISoftMaskProjectSettings.useStencilOutsideScreen;
_stencilBits = Utils.GetStencilBits(transform, true, useStencil, out _mask, out var _);
}
private void SetContainerDirty()
{
if (_container)
{
_container.SetContainerDirty();
}
}
private void SetMaterialDirty()
{
if (graphic)
{
var proxy = GraphicProxy.Find(graphic);
proxy.SetMaterialDirty(graphic);
}
}
private void UpdateContainer()
{
MaskingShapeContainer newContainer = null;
if (isActiveAndEnabled)
{
var useStencil = UISoftMaskProjectSettings.useStencilOutsideScreen;
Utils.GetStencilBits(transform, false, useStencil, out var mask, out var _);
if (!mask) return;
newContainer = mask.GetOrAddComponent<MaskingShapeContainer>();
}
if (newContainer != _container)
{
if (_container)
{
_container.Unregister(this);
}
if (newContainer)
{
newContainer.Register(this);
}
}
_container = newContainer;
}
internal bool IsInside(Vector2 sp, Camera eventCamera, float threshold = 0.01f)
{
if (!isActiveAndEnabled) return false;
{
Profiler.BeginSample("(SM4UI)[MaskingShape)] IsInside > Rectangle");
var inRectangle =
RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, sp, eventCamera);
Profiler.EndSample();
if (!inRectangle) return false;
}
if (alphaHitTest)
{
Profiler.BeginSample("(SM4UI)[MaskingShape)] IsInside > Alpha Hit Test");
var hit = Utils.AlphaHitTestValid(graphic, sp, eventCamera, threshold);
Profiler.EndSample();
if (!hit) return false;
}
return true;
}
internal void DrawSoftMaskBuffer(CommandBuffer cb, int depth)
{
var proxy = GraphicProxy.Find(graphic);
var texture = proxy.GetMainTexture(graphic);
var mesh = _mesh;
if (!mesh) return;
if (!graphic.IsInScreen()) return;
Profiler.BeginSample("(SM4UI)[MaskingShape)] DrawSoftMaskBuffer");
if (_mpb == null)
{
_mpb = SoftMaskUtils.materialPropertyBlockPool.Rent();
}
var alpha = proxy.GetAlpha(graphic);
SoftMaskUtils.ApplyMaterialPropertyBlock(_mpb, depth, texture, softnessRange, alpha);
var softMaterial = SoftMaskUtils.GetSoftMaskingMaterial(maskingMethod);
cb.DrawMesh(mesh, transform.localToWorldMatrix, softMaterial, 0, 0, _mpb);
Profiler.EndSample();
}
private void RegisterAntiAliasingIfNeeded()
{
if (_antiAliasingRegistered == AntiAliasingEnabled()) return;
if (!_antiAliasingRegistered)
{
_antiAliasingRegistered = true;
UIExtraCallbacks.onBeforeCanvasRebuild +=
_updateAntiAliasing ?? (_updateAntiAliasing = UpdateAntiAliasing);
UpdateAntiAliasing();
}
else
{
_antiAliasingRegistered = false;
UIExtraCallbacks.onBeforeCanvasRebuild -=
_updateAntiAliasing ?? (_updateAntiAliasing = UpdateAntiAliasing);
UpdateAntiAliasing();
}
}
private void UpdateAntiAliasing()
{
if (!this || !_graphic) return;
RecalculateStencilIfNeeded();
if (AntiAliasingEnabled())
{
Utils.UpdateAntiAlias(_graphic, true, antiAliasingThreshold);
}
else
{
Utils.UpdateAntiAlias(_graphic, false, 0);
}
}
}
}