备份CatanBuilding瘦身独立工程
This commit is contained in:
352
LocalPackages/SoftMaskForUGUI/Scripts/SoftMaskable.cs
Normal file
352
LocalPackages/SoftMaskForUGUI/Scripts/SoftMaskable.cs
Normal file
@@ -0,0 +1,352 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using UnityEngine.UI;
|
||||
using MaskIntr = UnityEngine.SpriteMaskInteraction;
|
||||
|
||||
namespace Coffee.UISoftMask
|
||||
{
|
||||
/// <summary>
|
||||
/// Soft maskable.
|
||||
/// Add this component to Graphic under SoftMask for smooth masking.
|
||||
/// </summary>
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
[ExecuteAlways]
|
||||
#else
|
||||
[ExecuteInEditMode]
|
||||
# endif
|
||||
[RequireComponent(typeof(Graphic))]
|
||||
public class SoftMaskable : MonoBehaviour, IMaterialModifier, ICanvasRaycastFilter
|
||||
#if UNITY_EDITOR
|
||||
, ISerializationCallbackReceiver
|
||||
# endif
|
||||
{
|
||||
private const int kVisibleInside = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6);
|
||||
private const int kVisibleOutside = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6);
|
||||
private static readonly Hash128 k_InvalidHash = new Hash128();
|
||||
|
||||
private static int s_RenderScale;
|
||||
private static int s_SoftMaskTexId;
|
||||
private static int s_StencilCompId;
|
||||
private static int s_MaskInteractionId;
|
||||
private static int s_GameVPId;
|
||||
private static int s_GameTVPId;
|
||||
private static List<SoftMaskable> s_ActiveSoftMaskables;
|
||||
private static int[] s_Interactions = new int[4];
|
||||
|
||||
[SerializeField, HideInInspector, System.Obsolete]
|
||||
private bool m_Inverse;
|
||||
|
||||
[SerializeField, Tooltip("The interaction for each masks."), HideInInspector]
|
||||
private int m_MaskInteraction = kVisibleInside;
|
||||
|
||||
[SerializeField, Tooltip("Use stencil to mask.")]
|
||||
private bool m_UseStencil = true;
|
||||
|
||||
[SerializeField, Tooltip("Use soft-masked raycast target.\n\nNote: This option is expensive.")]
|
||||
private bool m_RaycastFilter;
|
||||
|
||||
private Graphic _graphic;
|
||||
private SoftMask _softMask;
|
||||
private Hash128 _effectMaterialHash;
|
||||
|
||||
/// <summary>
|
||||
/// The graphic will be visible only in areas where no mask is present.
|
||||
/// </summary>
|
||||
public bool inverse
|
||||
{
|
||||
get { return m_MaskInteraction == kVisibleOutside; }
|
||||
set
|
||||
{
|
||||
var intValue = value ? kVisibleOutside : kVisibleInside;
|
||||
if (m_MaskInteraction == intValue) return;
|
||||
m_MaskInteraction = intValue;
|
||||
graphic.SetMaterialDirtyEx();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use soft-masked raycast target. This option is expensive.
|
||||
/// </summary>
|
||||
public bool raycastFilter
|
||||
{
|
||||
get { return m_RaycastFilter; }
|
||||
set { m_RaycastFilter = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use stencil to mask.
|
||||
/// </summary>
|
||||
public bool useStencil
|
||||
{
|
||||
get { return m_UseStencil; }
|
||||
set
|
||||
{
|
||||
if (m_UseStencil == value) return;
|
||||
m_UseStencil = value;
|
||||
graphic.SetMaterialDirtyEx();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The graphic associated with the soft mask.
|
||||
/// </summary>
|
||||
public Graphic graphic
|
||||
{
|
||||
get { return _graphic ? _graphic : _graphic = GetComponent<Graphic>(); }
|
||||
}
|
||||
|
||||
public SoftMask softMask
|
||||
{
|
||||
get { return _softMask ? _softMask : _softMask = this.GetComponentInParentEx<SoftMask>(); }
|
||||
}
|
||||
|
||||
public Material modifiedMaterial { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Perform material modification in this function.
|
||||
/// </summary>
|
||||
/// <returns>Modified material.</returns>
|
||||
/// <param name="baseMaterial">Configured Material.</param>
|
||||
Material IMaterialModifier.GetModifiedMaterial(Material baseMaterial)
|
||||
{
|
||||
_softMask = null;
|
||||
modifiedMaterial = null;
|
||||
|
||||
// If this component is disabled, the material is returned as is.
|
||||
// If the parents do not have a soft mask component, the material is returned as is.
|
||||
if (!isActiveAndEnabled || !softMask)
|
||||
{
|
||||
MaterialCache.Unregister(_effectMaterialHash);
|
||||
_effectMaterialHash = k_InvalidHash;
|
||||
return baseMaterial;
|
||||
}
|
||||
|
||||
// Generate soft maskable material.
|
||||
var previousHash = _effectMaterialHash;
|
||||
_effectMaterialHash = new Hash128(
|
||||
(uint) baseMaterial.GetInstanceID(),
|
||||
(uint) softMask.GetInstanceID(),
|
||||
(uint) m_MaskInteraction,
|
||||
(uint) (m_UseStencil ? 1 : 0)
|
||||
);
|
||||
|
||||
// Generate soft maskable material.
|
||||
modifiedMaterial = MaterialCache.Register(baseMaterial, _effectMaterialHash, mat =>
|
||||
{
|
||||
mat.shader = Shader.Find(string.Format("Hidden/{0} (SoftMaskable)", mat.shader.name));
|
||||
mat.SetFloat(s_RenderScale, UniversalRenderPipeline.asset.renderScale);
|
||||
mat.SetTexture(s_SoftMaskTexId, softMask.softMaskBuffer);
|
||||
mat.SetInt(s_StencilCompId, m_UseStencil ? (int) CompareFunction.Equal : (int) CompareFunction.Always);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
mat.EnableKeyword("SOFTMASK_EDITOR");
|
||||
UpdateMaterialForSceneView(mat);
|
||||
#endif
|
||||
|
||||
var root = MaskUtilities.FindRootSortOverrideCanvas(transform);
|
||||
var stencil = MaskUtilities.GetStencilDepth(transform, root);
|
||||
mat.SetVector(s_MaskInteractionId, new Vector4(
|
||||
1 <= stencil ? (m_MaskInteraction >> 0 & 0x3) : 0,
|
||||
2 <= stencil ? (m_MaskInteraction >> 2 & 0x3) : 0,
|
||||
3 <= stencil ? (m_MaskInteraction >> 4 & 0x3) : 0,
|
||||
4 <= stencil ? (m_MaskInteraction >> 6 & 0x3) : 0
|
||||
));
|
||||
});
|
||||
|
||||
// Unregister the previous material.
|
||||
MaterialCache.Unregister(previousHash);
|
||||
|
||||
return modifiedMaterial;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a point and a camera is the raycast valid.
|
||||
/// </summary>
|
||||
/// <returns>Valid.</returns>
|
||||
/// <param name="sp">Screen position.</param>
|
||||
/// <param name="eventCamera">Raycast camera.</param>
|
||||
bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
|
||||
{
|
||||
if (!isActiveAndEnabled || !softMask)
|
||||
return true;
|
||||
if (!RectTransformUtility.RectangleContainsScreenPoint(transform as RectTransform, sp, eventCamera))
|
||||
return false;
|
||||
|
||||
if (m_RaycastFilter)
|
||||
{
|
||||
var sm = _softMask;
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
s_Interactions[i] = sm ? ((m_MaskInteraction >> i * 2) & 0x3) : 0;
|
||||
sm = sm ? sm.parent : null;
|
||||
}
|
||||
|
||||
return _softMask.IsRaycastLocationValid(sp, eventCamera, graphic, s_Interactions);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sm = _softMask;
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
if (!sm) break;
|
||||
|
||||
s_Interactions[i] = sm ? ((m_MaskInteraction >> i * 2) & 0x3) : 0;
|
||||
var interaction = s_Interactions[i] == 1;
|
||||
var rt = sm.transform as RectTransform;
|
||||
var inRect = RectTransformUtility.RectangleContainsScreenPoint(rt, sp, eventCamera);
|
||||
if (!sm.ignoreSelfGraphic && interaction != inRect) return false;
|
||||
|
||||
foreach (var child in sm._children)
|
||||
{
|
||||
if (!child) continue;
|
||||
|
||||
var childRt = child.transform as RectTransform;
|
||||
var inRectChild = RectTransformUtility.RectangleContainsScreenPoint(childRt, sp, eventCamera);
|
||||
if (!child.ignoreSelfGraphic && interaction != inRectChild) return false;
|
||||
}
|
||||
|
||||
sm = sm ? sm.parent : null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the interaction for each mask.
|
||||
/// </summary>
|
||||
public void SetMaskInteraction(MaskIntr intr)
|
||||
{
|
||||
SetMaskInteraction(intr, intr, intr, intr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the interaction for each mask.
|
||||
/// </summary>
|
||||
public void SetMaskInteraction(MaskIntr layer0, MaskIntr layer1, MaskIntr layer2, MaskIntr layer3)
|
||||
{
|
||||
m_MaskInteraction = (int) layer0 + ((int) layer1 << 2) + ((int) layer2 << 4) + ((int) layer3 << 6);
|
||||
graphic.SetMaterialDirtyEx();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the object becomes enabled and active.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
// Register.
|
||||
if (s_ActiveSoftMaskables == null)
|
||||
{
|
||||
s_ActiveSoftMaskables = new List<SoftMaskable>();
|
||||
|
||||
s_RenderScale = Shader.PropertyToID("_RenderScale");
|
||||
s_SoftMaskTexId = Shader.PropertyToID("_SoftMaskTex");
|
||||
s_StencilCompId = Shader.PropertyToID("_StencilComp");
|
||||
s_MaskInteractionId = Shader.PropertyToID("_MaskInteraction");
|
||||
|
||||
#if UNITY_EDITOR
|
||||
s_GameVPId = Shader.PropertyToID("_GameVP");
|
||||
s_GameTVPId = Shader.PropertyToID("_GameTVP");
|
||||
#endif
|
||||
}
|
||||
|
||||
s_ActiveSoftMaskables.Add(this);
|
||||
|
||||
graphic.SetMaterialDirtyEx();
|
||||
_softMask = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the behaviour becomes disabled.
|
||||
/// </summary>
|
||||
private void OnDisable()
|
||||
{
|
||||
s_ActiveSoftMaskables.Remove(this);
|
||||
|
||||
graphic.SetMaterialDirtyEx();
|
||||
_softMask = null;
|
||||
|
||||
MaterialCache.Unregister(_effectMaterialHash);
|
||||
_effectMaterialHash = k_InvalidHash;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void UpdateMaterialForSceneView(Material mat)
|
||||
{
|
||||
if(!mat || !graphic || !graphic.canvas || !mat.shader || !mat.shader.name.EndsWith(" (SoftMaskable)")) return;
|
||||
|
||||
// Set view and projection matrices.
|
||||
Profiler.BeginSample("Set view and projection matrices");
|
||||
var c = graphic.canvas.rootCanvas;
|
||||
var cam = c.worldCamera ?? Camera.main;
|
||||
if (c && c.renderMode != RenderMode.ScreenSpaceOverlay && cam)
|
||||
{
|
||||
var p = GL.GetGPUProjectionMatrix(cam.projectionMatrix, false);
|
||||
var pv = p * cam.worldToCameraMatrix;
|
||||
mat.SetMatrix(s_GameVPId, pv);
|
||||
mat.SetMatrix(s_GameTVPId, pv);
|
||||
}
|
||||
else
|
||||
{
|
||||
var pos = c.transform.position;
|
||||
var scale = c.transform.localScale.x;
|
||||
var size = (c.transform as RectTransform).sizeDelta;
|
||||
var gameVp = Matrix4x4.TRS(new Vector3(0, 0, 0.5f), Quaternion.identity, new Vector3(2 / size.x, 2 / size.y, 0.0005f * scale));
|
||||
var gameTvp = Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, new Vector3(1 / pos.x, 1 / pos.y, -2 / 2000f)) * Matrix4x4.Translate(-pos);
|
||||
|
||||
mat.SetMatrix(s_GameVPId, gameVp);
|
||||
mat.SetMatrix(s_GameTVPId, gameTvp);
|
||||
}
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
UpdateMaterialForSceneView(modifiedMaterial);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).
|
||||
/// </summary>
|
||||
private void OnValidate()
|
||||
{
|
||||
graphic.SetMaterialDirtyEx();
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
#pragma warning disable 0612
|
||||
if (m_Inverse)
|
||||
{
|
||||
m_Inverse = false;
|
||||
m_MaskInteraction = kVisibleOutside;
|
||||
}
|
||||
#pragma warning restore 0612
|
||||
|
||||
var current = this;
|
||||
UnityEditor.EditorApplication.delayCall += () =>
|
||||
{
|
||||
if (!current) return;
|
||||
if (!graphic) return;
|
||||
if (graphic.name.Contains("TMP SubMeshUI")) return;
|
||||
if (!graphic.material) return;
|
||||
if (!graphic.material.shader) return;
|
||||
if (graphic.material.shader.name != "Hidden/UI/Default (SoftMaskable)") return;
|
||||
|
||||
graphic.material = null;
|
||||
graphic.SetMaterialDirtyEx();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user