close #31; Mask interaction for each layer
parent
a135ea1a25
commit
4e533c22bf
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
using MaskIntr = UnityEngine.SpriteMaskInteraction;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions.Editors
|
namespace Coffee.UIExtensions.Editors
|
||||||
|
@ -17,6 +18,38 @@ namespace Coffee.UIExtensions.Editors
|
||||||
[CanEditMultipleObjects]
|
[CanEditMultipleObjects]
|
||||||
public class SoftMaskableEditor : Editor
|
public class SoftMaskableEditor : Editor
|
||||||
{
|
{
|
||||||
|
//################################
|
||||||
|
// Constant or Static Members.
|
||||||
|
//################################
|
||||||
|
public enum MaskInteraction : int
|
||||||
|
{
|
||||||
|
VisibleInsideMask = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6),
|
||||||
|
VisibleOutsideMask = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6),
|
||||||
|
Custom = -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
MaskInteraction maskInteraction
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int value = _spMaskInteraction.intValue;
|
||||||
|
return _custom
|
||||||
|
? MaskInteraction.Custom
|
||||||
|
: System.Enum.IsDefined(typeof(MaskInteraction), value)
|
||||||
|
? (MaskInteraction)value
|
||||||
|
: MaskInteraction.Custom;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_custom = (value == MaskInteraction.Custom);
|
||||||
|
if (!_custom)
|
||||||
|
{
|
||||||
|
_spMaskInteraction.intValue = (int)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool _custom = false;
|
||||||
|
|
||||||
static readonly Type s_TypeTMPro = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Text");
|
static readonly Type s_TypeTMPro = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Text");
|
||||||
static readonly Type s_TypeTMP_SpriteAsset = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SpriteAsset");
|
static readonly Type s_TypeTMP_SpriteAsset = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SpriteAsset");
|
||||||
static readonly Type s_TypeTMProSettings = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Settings");
|
static readonly Type s_TypeTMProSettings = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Settings");
|
||||||
|
@ -36,9 +69,13 @@ namespace Coffee.UIExtensions.Editors
|
||||||
Shader _mobileShader;
|
Shader _mobileShader;
|
||||||
Shader _spriteShader;
|
Shader _spriteShader;
|
||||||
List<MaterialEditor> _materialEditors = new List<MaterialEditor> ();
|
List<MaterialEditor> _materialEditors = new List<MaterialEditor> ();
|
||||||
|
SerializedProperty _spMaskInteraction;
|
||||||
|
|
||||||
private void OnEnable ()
|
private void OnEnable ()
|
||||||
{
|
{
|
||||||
|
_spMaskInteraction = serializedObject.FindProperty("m_MaskInteraction");
|
||||||
|
_custom = (maskInteraction == MaskInteraction.Custom);
|
||||||
|
|
||||||
ClearMaterialEditors ();
|
ClearMaterialEditors ();
|
||||||
|
|
||||||
_shader = Shader.Find ("TextMeshPro/Distance Field (SoftMaskable)");
|
_shader = Shader.Find ("TextMeshPro/Distance Field (SoftMaskable)");
|
||||||
|
@ -58,6 +95,8 @@ namespace Coffee.UIExtensions.Editors
|
||||||
s_PiDefaultFontAssetPath = s_TypeTMProSettings.GetProperty ("defaultFontAssetPath", BindingFlags.Static | BindingFlags.Public);
|
s_PiDefaultFontAssetPath = s_TypeTMProSettings.GetProperty ("defaultFontAssetPath", BindingFlags.Static | BindingFlags.Public);
|
||||||
s_PiDefaultSpriteAssetPath = s_TypeTMProSettings.GetProperty ("defaultSpriteAssetPath", BindingFlags.Static | BindingFlags.Public);
|
s_PiDefaultSpriteAssetPath = s_TypeTMProSettings.GetProperty ("defaultSpriteAssetPath", BindingFlags.Static | BindingFlags.Public);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_MaskWarning = new GUIContent(EditorGUIUtility.FindTexture("console.warnicon.sml"), "This component is not SoftMask. Use SoftMask instead of Mask.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDisable ()
|
private void OnDisable ()
|
||||||
|
@ -65,10 +104,105 @@ namespace Coffee.UIExtensions.Editors
|
||||||
ClearMaterialEditors ();
|
ClearMaterialEditors ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Mask> tmpMasks = new List<Mask>();
|
||||||
|
|
||||||
|
void DrawMaskInteractions()
|
||||||
|
{
|
||||||
|
(target as SoftMaskable).GetComponentsInParent<Mask>(true, tmpMasks);
|
||||||
|
tmpMasks.RemoveAll(x => !x.enabled);
|
||||||
|
tmpMasks.Reverse();
|
||||||
|
|
||||||
|
maskInteraction = (MaskInteraction)EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction);
|
||||||
|
if (_custom)
|
||||||
|
{
|
||||||
|
var l = EditorGUIUtility.labelWidth;
|
||||||
|
EditorGUIUtility.labelWidth = 45;
|
||||||
|
|
||||||
|
using (var ccs = new EditorGUI.ChangeCheckScope())
|
||||||
|
{
|
||||||
|
int intr0 = DrawMaskInteraction(0);
|
||||||
|
int intr1 = DrawMaskInteraction(1);
|
||||||
|
int intr2 = DrawMaskInteraction(2);
|
||||||
|
int intr3 = DrawMaskInteraction(3);
|
||||||
|
|
||||||
|
if (ccs.changed) {
|
||||||
|
_spMaskInteraction.intValue = (intr0 << 0) + (intr1 << 2) + (intr2 << 4) + (intr3 << 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUIUtility.labelWidth = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GUIContent s_MaskWarning = new GUIContent();
|
||||||
|
|
||||||
|
int DrawMaskInteraction(int layer)
|
||||||
|
{
|
||||||
|
Mask mask = layer < tmpMasks.Count ? tmpMasks[layer] : null;
|
||||||
|
MaskIntr intr = (MaskIntr)((_spMaskInteraction.intValue >> layer * 2) & 0x3);
|
||||||
|
if (!mask)
|
||||||
|
{
|
||||||
|
return (int)intr;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (new EditorGUILayout.HorizontalScope())
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField(mask is SoftMask ? GUIContent.none : s_MaskWarning, GUILayout.Width(16));
|
||||||
|
GUILayout.Space(-5);
|
||||||
|
EditorGUILayout.ObjectField("Mask " + layer, mask, typeof(Mask), false);
|
||||||
|
GUILayout.Space(-15);
|
||||||
|
return (int)(MaskIntr)EditorGUILayout.EnumPopup(intr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnInspectorGUI ()
|
public override void OnInspectorGUI ()
|
||||||
{
|
{
|
||||||
base.OnInspectorGUI ();
|
base.OnInspectorGUI ();
|
||||||
|
|
||||||
|
serializedObject.Update();
|
||||||
|
DrawMaskInteractions();
|
||||||
|
|
||||||
|
// maskInteraction = (MaskInteraction)EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction);
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
/*
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
var l = EditorGUIUtility.labelWidth;
|
||||||
|
EditorGUIUtility.labelWidth = 60;
|
||||||
|
using (new EditorGUILayout.HorizontalScope())
|
||||||
|
{
|
||||||
|
EditorGUILayout.ObjectField("Mask 0", null, typeof(Mask), false);
|
||||||
|
EditorGUILayout.EnumPopup (MaskIntr.None);
|
||||||
|
}
|
||||||
|
EditorGUIUtility.labelWidth = l;
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
|
||||||
|
var spMaskInteraction = serializedObject.FindProperty ("m_MaskInteraction");
|
||||||
|
MaskIntr intr0 = (MaskIntr)((spMaskInteraction.intValue >> 0) & 0x3);
|
||||||
|
MaskIntr intr1 = (MaskIntr)((spMaskInteraction.intValue >> 2) & 0x3);
|
||||||
|
MaskIntr intr2 = (MaskIntr)((spMaskInteraction.intValue >> 4) & 0x3);
|
||||||
|
MaskIntr intr3 = (MaskIntr)((spMaskInteraction.intValue >> 6) & 0x3);
|
||||||
|
|
||||||
|
using (var ccs = new EditorGUI.ChangeCheckScope ()) {
|
||||||
|
|
||||||
|
intr0 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 0", intr0);
|
||||||
|
intr1 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 1", intr1);
|
||||||
|
intr2 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 2", intr2);
|
||||||
|
intr3 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 3", intr3);
|
||||||
|
|
||||||
|
if (ccs.changed) {
|
||||||
|
current.SetMaskInteractions (intr0,intr1,intr2,intr3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// spMaskInteraction.intValue = (intr0 << 0) | (intr1 << 2) | (intr2 << 4) | (intr3 << 6);
|
||||||
|
//
|
||||||
|
// serializedObject.ApplyModifiedProperties ();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// var current = target as SoftMaskable;
|
||||||
var current = target as SoftMaskable;
|
var current = target as SoftMaskable;
|
||||||
current.GetComponentsInChildren<Graphic> (true, s_Graphics);
|
current.GetComponentsInChildren<Graphic> (true, s_Graphics);
|
||||||
var fixTargets = s_Graphics.Where (x => x.gameObject != current.gameObject && !x.GetComponent<SoftMaskable> () && (!x.GetComponent<Mask> () || x.GetComponent<Mask> ().showMaskGraphic)).ToList ();
|
var fixTargets = s_Graphics.Where (x => x.gameObject != current.gameObject && !x.GetComponent<SoftMaskable> () && (!x.GetComponent<Mask> () || x.GetComponent<Mask> ().showMaskGraphic)).ToList ();
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Coffee.UIExtensions
|
||||||
/// Soft mask.
|
/// Soft mask.
|
||||||
/// Use instead of Mask for smooth masking.
|
/// Use instead of Mask for smooth masking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SoftMask : Mask, IMeshModifier, ICanvasRaycastFilter
|
public class SoftMask : Mask, IMeshModifier
|
||||||
{
|
{
|
||||||
//################################
|
//################################
|
||||||
// Constant or Static Members.
|
// Constant or Static Members.
|
||||||
|
@ -106,7 +106,7 @@ namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
m_IgnoreParent = value;
|
m_IgnoreParent = value;
|
||||||
hasChanged = true;
|
hasChanged = true;
|
||||||
OnTransformParentChanged ();
|
OnTransformParentChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,9 +132,9 @@ namespace Coffee.UIExtensions
|
||||||
ReleaseRT(ref _softMaskBuffer);
|
ReleaseRT(ref _softMaskBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_softMaskBuffer)
|
if (!_softMaskBuffer)
|
||||||
{
|
{
|
||||||
_softMaskBuffer = RenderTexture.GetTemporary (w, h, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
|
_softMaskBuffer = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
|
||||||
hasChanged = true;
|
hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ namespace Coffee.UIExtensions
|
||||||
}
|
}
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
if(_parent)
|
if (_parent)
|
||||||
{
|
{
|
||||||
_parent.hasChanged = value;
|
_parent.hasChanged = value;
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,15 @@ namespace Coffee.UIExtensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SoftMask parent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perform material modification in this function.
|
/// Perform material modification in this function.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -203,34 +212,23 @@ namespace Coffee.UIExtensions
|
||||||
/// <param name="sp">Screen position.</param>
|
/// <param name="sp">Screen position.</param>
|
||||||
/// <param name="eventCamera">Raycast camera.</param>
|
/// <param name="eventCamera">Raycast camera.</param>
|
||||||
/// <param name="g">Target graphic.</param>
|
/// <param name="g">Target graphic.</param>
|
||||||
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera, Graphic g)
|
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera, Graphic g, int[] interactions)
|
||||||
{
|
{
|
||||||
if (!isActiveAndEnabled || (g == graphic && !g.raycastTarget))
|
if (!isActiveAndEnabled || (g == graphic && !g.raycastTarget))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!RectTransformUtility.RectangleContainsScreenPoint(rectTransform, sp, eventCamera))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int x = (int)(softMaskBuffer.width * sp.x / Screen.width);
|
int x = (int)(softMaskBuffer.width * sp.x / Screen.width);
|
||||||
int y = (int)(softMaskBuffer.height * sp.y / Screen.height);
|
int y = (int)(softMaskBuffer.height * sp.y / Screen.height);
|
||||||
return 0.5f < GetPixelValue(x, y);
|
return 0.5f < GetPixelValue(x, y, interactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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>
|
|
||||||
public override bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
|
public override bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
|
||||||
{
|
{
|
||||||
return IsRaycastLocationValid(sp, eventCamera, graphic);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//################################
|
//################################
|
||||||
// Protected Members.
|
// Protected Members.
|
||||||
//################################
|
//################################
|
||||||
|
@ -329,12 +327,12 @@ namespace Coffee.UIExtensions
|
||||||
hasChanged = true;
|
hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRectTransformDimensionsChange ()
|
protected override void OnRectTransformDimensionsChange()
|
||||||
{
|
{
|
||||||
hasChanged = true;
|
hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).
|
/// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -382,13 +380,13 @@ namespace Coffee.UIExtensions
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var rt = sm.rectTransform;
|
var rt = sm.rectTransform;
|
||||||
if(rt.hasChanged)
|
if (rt.hasChanged)
|
||||||
{
|
{
|
||||||
rt.hasChanged = false;
|
rt.hasChanged = false;
|
||||||
sm.hasChanged = true;
|
sm.hasChanged = true;
|
||||||
}
|
}
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if(!Application.isPlaying)
|
if (!Application.isPlaying)
|
||||||
{
|
{
|
||||||
sm.hasChanged = true;
|
sm.hasChanged = true;
|
||||||
}
|
}
|
||||||
|
@ -403,7 +401,7 @@ namespace Coffee.UIExtensions
|
||||||
sm._hasChanged = false;
|
sm._hasChanged = false;
|
||||||
if (!sm._parent)
|
if (!sm._parent)
|
||||||
{
|
{
|
||||||
sm.UpdateMaskTexture ();
|
sm.UpdateMaskTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,13 +411,12 @@ namespace Coffee.UIExtensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void UpdateMaskTexture()
|
void UpdateMaskTexture()
|
||||||
{
|
{
|
||||||
if(!graphic || !graphic.canvas)
|
if (!graphic || !graphic.canvas)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform stopAfter = MaskUtilities.FindRootSortOverrideCanvas(transform);
|
_stencilDepth = MaskUtilities.GetStencilDepth(transform, MaskUtilities.FindRootSortOverrideCanvas(transform));
|
||||||
_stencilDepth = MaskUtilities.GetStencilDepth(transform, stopAfter);
|
|
||||||
|
|
||||||
// Collect children soft masks.
|
// Collect children soft masks.
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
|
@ -448,9 +445,9 @@ namespace Coffee.UIExtensions
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var pos = c.transform.localPosition;
|
var pos = c.transform.localPosition;
|
||||||
var vm = Matrix4x4.TRS (-pos, Quaternion.identity, new Vector3 (1, 1, -1f));
|
var vm = Matrix4x4.TRS(-pos, Quaternion.identity, new Vector3(1, 1, -1f));
|
||||||
var pm = Matrix4x4.TRS (new Vector3 (0, 0, -1), Quaternion.identity, new Vector3 (1 / pos.x, 1 / pos.y, -2 / 1000f));
|
var pm = Matrix4x4.TRS(new Vector3(0, 0, -1), Quaternion.identity, new Vector3(1 / pos.x, 1 / pos.y, -2 / 1000f));
|
||||||
_cb.SetViewProjectionMatrices (vm, pm);
|
_cb.SetViewProjectionMatrices(vm, pm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw soft masks.
|
// Draw soft masks.
|
||||||
|
@ -461,6 +458,11 @@ namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
var sm = s_TmpSoftMasks[i][j];
|
var sm = s_TmpSoftMasks[i][j];
|
||||||
|
|
||||||
|
if (i != 0)
|
||||||
|
{
|
||||||
|
sm._stencilDepth = MaskUtilities.GetStencilDepth(sm.transform, MaskUtilities.FindRootSortOverrideCanvas(sm.transform));
|
||||||
|
}
|
||||||
|
|
||||||
// Set material property.
|
// Set material property.
|
||||||
sm.material.SetInt(s_ColorMaskId, (int)1 << (3 - _stencilDepth - i));
|
sm.material.SetInt(s_ColorMaskId, (int)1 << (3 - _stencilDepth - i));
|
||||||
sm._mpb.SetTexture(s_MainTexId, sm.graphic.mainTexture);
|
sm._mpb.SetTexture(s_MainTexId, sm.graphic.mainTexture);
|
||||||
|
@ -562,7 +564,7 @@ namespace Coffee.UIExtensions
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the pixel value.
|
/// Gets the pixel value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
float GetPixelValue(int x, int y)
|
float GetPixelValue(int x, int y, int[] interactions)
|
||||||
{
|
{
|
||||||
if (!s_ReadTexture)
|
if (!s_ReadTexture)
|
||||||
{
|
{
|
||||||
|
@ -576,18 +578,23 @@ namespace Coffee.UIExtensions
|
||||||
RenderTexture.active = currentRT;
|
RenderTexture.active = currentRT;
|
||||||
|
|
||||||
var colors = s_ReadTexture.GetRawTextureData();
|
var colors = s_ReadTexture.GetRawTextureData();
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
switch (interactions[(i + 3)%4])
|
||||||
|
{
|
||||||
|
case 0: colors[i] = 255; break;
|
||||||
|
case 2: colors[i] = (byte)(255 - colors[i]); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (_stencilDepth)
|
switch (_stencilDepth)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0: return (colors[1] / 255f);
|
||||||
return (colors[1] / 255f);
|
case 1: return (colors[1] / 255f) * (colors[2] / 255f);
|
||||||
case 1:
|
case 2: return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f);
|
||||||
return (colors[1] / 255f) * (colors[2] / 255f);
|
case 3: return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f) * (colors[0] / 255f);
|
||||||
case 2:
|
default: return 0;
|
||||||
return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f);
|
|
||||||
case 3:
|
|
||||||
return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f) * (colors[0] / 255f);
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using MaskIntr = UnityEngine.SpriteMaskInteraction;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
|
@ -11,20 +13,27 @@ namespace Coffee.UIExtensions
|
||||||
/// Add this component to Graphic under SoftMask for smooth masking.
|
/// Add this component to Graphic under SoftMask for smooth masking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ExecuteInEditMode]
|
[ExecuteInEditMode]
|
||||||
public class SoftMaskable : MonoBehaviour, IMaterialModifier, ICanvasRaycastFilter
|
public class SoftMaskable : MonoBehaviour, IMaterialModifier, ICanvasRaycastFilter, ISerializationCallbackReceiver
|
||||||
{
|
{
|
||||||
//################################
|
//################################
|
||||||
// Constant or Static Members.
|
// Constant or Static Members.
|
||||||
//################################
|
//################################
|
||||||
static List<SoftMaskable> s_ActiveSoftMaskables;
|
const int kVisibleInside = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6);
|
||||||
static Material defaultMaterial = null;
|
const int kVisibleOutside = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6);
|
||||||
|
|
||||||
|
|
||||||
//################################
|
//################################
|
||||||
// Serialize Members.
|
// Serialize Members.
|
||||||
//################################
|
//################################
|
||||||
[Tooltip("The graphic will be visible only in areas where no mask is present.")]
|
[Tooltip("The graphic will be visible only in areas where no mask is present.")]
|
||||||
|
[System.Obsolete]
|
||||||
|
[HideInInspector]
|
||||||
[SerializeField] bool m_Inverse = false;
|
[SerializeField] bool m_Inverse = false;
|
||||||
|
[Tooltip("The interaction for each masks.")]
|
||||||
|
[HideInInspector]
|
||||||
|
[SerializeField] int m_MaskInteraction = kVisibleInside;
|
||||||
|
[Tooltip("Use stencil for masking.")]
|
||||||
|
[SerializeField] bool m_UseStencil = true;
|
||||||
|
|
||||||
|
|
||||||
//################################
|
//################################
|
||||||
|
@ -62,17 +71,13 @@ namespace Coffee.UIExtensions
|
||||||
result = new Material(baseMaterial);
|
result = new Material(baseMaterial);
|
||||||
result.hideFlags = HideFlags.HideAndDontSave;
|
result.hideFlags = HideFlags.HideAndDontSave;
|
||||||
result.SetTexture(s_SoftMaskTexId, _softMask.softMaskBuffer);
|
result.SetTexture(s_SoftMaskTexId, _softMask.softMaskBuffer);
|
||||||
|
result.SetInt(s_StencilCompId, m_UseStencil ? (int)CompareFunction.Equal : (int)CompareFunction.Always);
|
||||||
if (m_Inverse)
|
result.SetVector(s_MaskInteractionId, new Vector4(
|
||||||
{
|
(m_MaskInteraction & 0x3),
|
||||||
result.SetFloat(s_SoftMaskInverseId, 1);
|
((m_MaskInteraction >> 2) & 0x3),
|
||||||
result.SetInt(s_StencilCompId, (int)CompareFunction.Always);
|
((m_MaskInteraction >> 4) & 0x3),
|
||||||
}
|
((m_MaskInteraction >> 6) & 0x3)
|
||||||
else
|
));
|
||||||
{
|
|
||||||
result.SetFloat(s_SoftMaskInverseId, 0);
|
|
||||||
result.SetInt(s_StencilCompId, (int)CompareFunction.Equal);
|
|
||||||
}
|
|
||||||
|
|
||||||
StencilMaterial.Remove(baseMaterial);
|
StencilMaterial.Remove(baseMaterial);
|
||||||
ReleaseMaterial(ref _maskMaterial);
|
ReleaseMaterial(ref _maskMaterial);
|
||||||
|
@ -103,22 +108,34 @@ namespace Coffee.UIExtensions
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!RectTransformUtility.RectangleContainsScreenPoint(transform as RectTransform, sp, eventCamera))
|
if (!RectTransformUtility.RectangleContainsScreenPoint(transform as RectTransform, sp, eventCamera))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _softMask.IsRaycastLocationValid(sp, eventCamera, graphic) != m_Inverse;
|
var sm = _softMask;
|
||||||
|
for (int 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The graphic will be visible only in areas where no mask is present.
|
/// The graphic will be visible only in areas where no mask is present.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[System.Obsolete("Use SetMaskInteractions method instead.")]
|
||||||
public bool inverse
|
public bool inverse
|
||||||
{
|
{
|
||||||
get { return m_Inverse; }
|
get { return m_MaskInteraction == kVisibleOutside; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (m_Inverse != value)
|
int intValue = value ? kVisibleOutside : kVisibleInside;
|
||||||
|
if (m_MaskInteraction != intValue)
|
||||||
{
|
{
|
||||||
m_Inverse = value;
|
m_MaskInteraction = intValue;
|
||||||
graphic.SetMaterialDirty();
|
graphic.SetMaterialDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +146,25 @@ namespace Coffee.UIExtensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Graphic graphic{ get { return _graphic ? _graphic : _graphic = GetComponent<Graphic>(); } }
|
public Graphic graphic{ get { return _graphic ? _graphic : _graphic = GetComponent<Graphic>(); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the interaction for each mask.
|
||||||
|
/// </summary>
|
||||||
|
public void SetMaskInteraction(SpriteMaskInteraction intr)
|
||||||
|
{
|
||||||
|
SetMaskInteraction(intr, intr, intr, intr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the interaction for each mask.
|
||||||
|
/// </summary>
|
||||||
|
public void SetMaskInteraction(SpriteMaskInteraction layer0, SpriteMaskInteraction layer1, SpriteMaskInteraction layer2, SpriteMaskInteraction layer3)
|
||||||
|
{
|
||||||
|
m_MaskInteraction = (int)layer0 + ((int)layer1 << 2) + ((int)layer2 << 4) + ((int)layer3 << 6);
|
||||||
|
if (graphic)
|
||||||
|
{
|
||||||
|
graphic.SetMaterialDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//################################
|
//################################
|
||||||
// Private Members.
|
// Private Members.
|
||||||
|
@ -138,7 +174,10 @@ namespace Coffee.UIExtensions
|
||||||
Material _maskMaterial = null;
|
Material _maskMaterial = null;
|
||||||
static int s_SoftMaskTexId;
|
static int s_SoftMaskTexId;
|
||||||
static int s_StencilCompId;
|
static int s_StencilCompId;
|
||||||
static int s_SoftMaskInverseId;
|
static int s_MaskInteractionId;
|
||||||
|
static List<SoftMaskable> s_ActiveSoftMaskables;
|
||||||
|
static int[] s_Interactions = new int[4];
|
||||||
|
static Material s_DefaultMaterial;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -158,13 +197,13 @@ namespace Coffee.UIExtensions
|
||||||
|
|
||||||
foreach (var sm in s_ActiveSoftMaskables)
|
foreach (var sm in s_ActiveSoftMaskables)
|
||||||
{
|
{
|
||||||
if(sm)
|
if (sm)
|
||||||
{
|
{
|
||||||
Material mat = sm._maskMaterial;
|
Material mat = sm._maskMaterial;
|
||||||
if (mat)
|
if (mat)
|
||||||
{
|
{
|
||||||
mat.SetMatrix ("_SceneView", w2c);
|
mat.SetMatrix("_SceneView", w2c);
|
||||||
mat.SetMatrix ("_SceneProj", prj);
|
mat.SetMatrix("_SceneProj", prj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,7 +237,7 @@ namespace Coffee.UIExtensions
|
||||||
|
|
||||||
s_SoftMaskTexId = Shader.PropertyToID("_SoftMaskTex");
|
s_SoftMaskTexId = Shader.PropertyToID("_SoftMaskTex");
|
||||||
s_StencilCompId = Shader.PropertyToID("_StencilComp");
|
s_StencilCompId = Shader.PropertyToID("_StencilComp");
|
||||||
s_SoftMaskInverseId = Shader.PropertyToID("_SoftMaskInverse");
|
s_MaskInteractionId = Shader.PropertyToID("_MaskInteraction");
|
||||||
}
|
}
|
||||||
s_ActiveSoftMaskables.Add(this);
|
s_ActiveSoftMaskables.Add(this);
|
||||||
|
|
||||||
|
@ -208,7 +247,7 @@ namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
if (!g.material || g.material == Graphic.defaultGraphicMaterial)
|
if (!g.material || g.material == Graphic.defaultGraphicMaterial)
|
||||||
{
|
{
|
||||||
g.material = defaultMaterial ?? (defaultMaterial = new Material (Resources.Load<Shader> ("UI-Default-SoftMask")) { hideFlags = HideFlags.HideAndDontSave, });
|
g.material = s_DefaultMaterial ?? (s_DefaultMaterial = new Material(Resources.Load<Shader>("UI-Default-SoftMask")) { hideFlags = HideFlags.HideAndDontSave, });
|
||||||
}
|
}
|
||||||
g.SetMaterialDirty();
|
g.SetMaterialDirty();
|
||||||
}
|
}
|
||||||
|
@ -225,7 +264,7 @@ namespace Coffee.UIExtensions
|
||||||
var g = graphic;
|
var g = graphic;
|
||||||
if (g)
|
if (g)
|
||||||
{
|
{
|
||||||
if (g.material == defaultMaterial)
|
if (g.material == s_DefaultMaterial)
|
||||||
{
|
{
|
||||||
g.material = null;
|
g.material = null;
|
||||||
}
|
}
|
||||||
|
@ -258,5 +297,19 @@ namespace Coffee.UIExtensions
|
||||||
mat = null;
|
mat = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||||
|
{
|
||||||
|
if (m_Inverse)
|
||||||
|
{
|
||||||
|
m_Inverse = false;
|
||||||
|
m_MaskInteraction = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,11 +2,10 @@
|
||||||
#define UI_SOFTMASK_INCLUDED
|
#define UI_SOFTMASK_INCLUDED
|
||||||
|
|
||||||
sampler2D _SoftMaskTex;
|
sampler2D _SoftMaskTex;
|
||||||
fixed _SoftMaskInverse;
|
|
||||||
float _Stencil;
|
float _Stencil;
|
||||||
float4x4 _SceneView;
|
float4x4 _SceneView;
|
||||||
float4x4 _SceneProj;
|
float4x4 _SceneProj;
|
||||||
|
half4 _MaskInteraction;
|
||||||
|
|
||||||
fixed Approximately(float4x4 a, float4x4 b)
|
fixed Approximately(float4x4 a, float4x4 b)
|
||||||
{
|
{
|
||||||
|
@ -19,6 +18,13 @@ fixed Approximately(float4x4 a, float4x4 b)
|
||||||
0.01);
|
0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fixed GetMaskAlpha(fixed alpha, fixed stencilId, fixed interaction)
|
||||||
|
{
|
||||||
|
fixed onStencil = step(stencilId, _Stencil);
|
||||||
|
alpha = lerp(1, alpha, onStencil * step(1, interaction));
|
||||||
|
return lerp(alpha, 1 - alpha, onStencil * step(2, interaction));
|
||||||
|
}
|
||||||
|
|
||||||
half SoftMask(float4 clipPos)
|
half SoftMask(float4 clipPos)
|
||||||
{
|
{
|
||||||
half2 view = clipPos.xy/_ScreenParams.xy;
|
half2 view = clipPos.xy/_ScreenParams.xy;
|
||||||
|
@ -26,13 +32,11 @@ half SoftMask(float4 clipPos)
|
||||||
view.y = 1.0 - view.y;
|
view.y = 1.0 - view.y;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
half alpha =
|
fixed4 mask = tex2D(_SoftMaskTex, view);
|
||||||
lerp(1, tex2D(_SoftMaskTex, view).a, step(15, _Stencil))
|
half alpha = GetMaskAlpha(mask.x, 1, _MaskInteraction.x)
|
||||||
* lerp(1, tex2D(_SoftMaskTex, view).b, step(7, _Stencil))
|
* GetMaskAlpha(mask.y, 3, _MaskInteraction.y)
|
||||||
* lerp(1, tex2D(_SoftMaskTex, view).g, step(3, _Stencil))
|
* GetMaskAlpha(mask.z, 7, _MaskInteraction.z)
|
||||||
* lerp(1, tex2D(_SoftMaskTex, view).r, step(1, _Stencil));
|
* GetMaskAlpha(mask.w, 15, _MaskInteraction.w);
|
||||||
|
|
||||||
alpha = lerp(alpha, 1 - alpha, _SoftMaskInverse);
|
|
||||||
|
|
||||||
#if SOFTMASK_EDITOR
|
#if SOFTMASK_EDITOR
|
||||||
fixed isSceneView = max(Approximately(UNITY_MATRIX_V, _SceneView), Approximately(UNITY_MATRIX_P, _SceneProj));
|
fixed isSceneView = max(Approximately(UNITY_MATRIX_V, _SceneView), Approximately(UNITY_MATRIX_P, _SceneProj));
|
||||||
|
@ -42,5 +46,4 @@ half SoftMask(float4 clipPos)
|
||||||
return alpha;
|
return alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // UI_SOFTMASK_INCLUDED
|
#endif // UI_SOFTMASK_INCLUDED
|
Loading…
Reference in New Issue