close #31; Mask interaction for each layer

pull/87/head
mob-sakai 2019-01-26 21:30:41 +09:00
parent a135ea1a25
commit 4e533c22bf
4 changed files with 274 additions and 77 deletions

View File

@ -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 ();

View File

@ -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;
} }
} }
} }

View File

@ -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);
}
}
} }
} }

View File

@ -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