Impl unmask
commit
9d7d8f6a66
|
|
@ -0,0 +1 @@
|
|||
./../../../../CHANGELOG.md
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fbca627d531eb4ca9b5846c638709e4c
|
||||
timeCreated: 1539214410
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1 @@
|
|||
./../../../../LICENSE.txt
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cefd86cfe94614a08ac447d0a9ec6ad3
|
||||
timeCreated: 1539214411
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6c5f8a1ac798e442eb3c77b05470878d
|
||||
timeCreated: 1539214410
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 50a872063d2754fcd9d092eab7677003
|
||||
folderAsset: yes
|
||||
timeCreated: 1539214485
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reverse masking for parent Mask component.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
[AddComponentMenu("UI/Unmask/Unmask", 1)]
|
||||
public class Unmask : MonoBehaviour, IMaterialModifier
|
||||
{
|
||||
//################################
|
||||
// Constant or Static Members.
|
||||
//################################
|
||||
static readonly Vector2 s_Center = new Vector2(0.5f, 0.5f);
|
||||
|
||||
|
||||
//################################
|
||||
// Serialize Members.
|
||||
//################################
|
||||
[Tooltip("Fit graphic's transform to target transform on LateUpdate.")]
|
||||
[SerializeField] RectTransform m_AutoFitTarget;
|
||||
[Tooltip("Show the graphic that is associated with the unmask render area.")]
|
||||
[SerializeField] bool m_ShowUnmaskGraphic = false;
|
||||
|
||||
|
||||
//################################
|
||||
// Public Members.
|
||||
//################################
|
||||
/// <summary>
|
||||
/// The graphic associated with the unmask.
|
||||
/// </summary>
|
||||
public Graphic graphic{ get { return _graphic ?? (_graphic = GetComponent<Graphic>()); } }
|
||||
|
||||
/// <summary>
|
||||
/// Fit graphic's transform to target transform on LateUpdate.
|
||||
/// </summary>
|
||||
public RectTransform autoFitTarget{ get { return m_AutoFitTarget; } set { m_AutoFitTarget = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Show the graphic that is associated with the unmask render area.
|
||||
/// </summary>
|
||||
public bool showUnmaskGraphic
|
||||
{
|
||||
get { return m_ShowUnmaskGraphic; }
|
||||
set
|
||||
{
|
||||
m_ShowUnmaskGraphic = value;
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform material modification in this function.
|
||||
/// </summary>
|
||||
/// <returns>Modified material.</returns>
|
||||
/// <param name="baseMaterial">Configured Material.</param>
|
||||
public Material GetModifiedMaterial(Material baseMaterial)
|
||||
{
|
||||
if (!isActiveAndEnabled)
|
||||
{
|
||||
return baseMaterial;
|
||||
}
|
||||
|
||||
Transform stopAfter = MaskUtilities.FindRootSortOverrideCanvas(transform);
|
||||
var stencilDepth = MaskUtilities.GetStencilDepth(transform, stopAfter);
|
||||
|
||||
StencilMaterial.Remove(_unmaskMaterial);
|
||||
_unmaskMaterial = StencilMaterial.Add(baseMaterial, (1 << stencilDepth) - 1, StencilOp.Zero, CompareFunction.Always, m_ShowUnmaskGraphic ? ColorWriteMask.All : (ColorWriteMask)0, 0, (1 << stencilDepth) - 1);
|
||||
//StencilMaterial.Remove (baseMaterial);
|
||||
|
||||
return _unmaskMaterial;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fit to target transform.
|
||||
/// </summary>
|
||||
/// <param name="target">Target transform.</param>
|
||||
public void FitTo(RectTransform target)
|
||||
{
|
||||
var rt = transform as RectTransform;
|
||||
|
||||
rt.position = target.position;
|
||||
rt.rotation = target.rotation;
|
||||
|
||||
var s1 = target.lossyScale;
|
||||
var s2 = rt.parent.lossyScale;
|
||||
rt.localScale = new Vector3(s1.x / s2.x, s1.y / s2.y, s1.z / s2.z);
|
||||
rt.sizeDelta = target.rect.size;
|
||||
rt.anchorMax = rt.anchorMin = s_Center;
|
||||
}
|
||||
|
||||
|
||||
//################################
|
||||
// Private Members.
|
||||
//################################
|
||||
Material _unmaskMaterial;
|
||||
Graphic _graphic;
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the object becomes enabled and active.
|
||||
/// </summary>
|
||||
void OnEnable()
|
||||
{
|
||||
if (m_AutoFitTarget)
|
||||
{
|
||||
FitTo(m_AutoFitTarget);
|
||||
}
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the behaviour becomes disabled () or inactive.
|
||||
/// </summary>
|
||||
void OnDisable()
|
||||
{
|
||||
StencilMaterial.Remove(_unmaskMaterial);
|
||||
_unmaskMaterial = null;
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LateUpdate is called every frame, if the Behaviour is enabled.
|
||||
/// </summary>
|
||||
void LateUpdate()
|
||||
{
|
||||
if (m_AutoFitTarget)
|
||||
{
|
||||
FitTo(m_AutoFitTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).
|
||||
/// </summary>
|
||||
void OnValidate()
|
||||
{
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the graphic as dirty.
|
||||
/// </summary>
|
||||
void SetDirty()
|
||||
{
|
||||
if (graphic)
|
||||
{
|
||||
graphic.SetMaterialDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f752d3a51152f4e44a3ebe45ae24abcc
|
||||
timeCreated: 1539214502
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Unmask Raycast Filter.
|
||||
/// The ray passes through the unmasked rectangle.
|
||||
/// </summary>
|
||||
[AddComponentMenu("UI/Unmask/UnmaskRaycastFilter", 2)]
|
||||
public class UnmaskRaycastFilter : MonoBehaviour, ICanvasRaycastFilter
|
||||
{
|
||||
//################################
|
||||
// Constant or Static Members.
|
||||
//################################
|
||||
Vector3[] s_WorldCorners = new Vector3[4];
|
||||
|
||||
|
||||
//################################
|
||||
// Serialize Members.
|
||||
//################################
|
||||
[Tooltip("Target unmask component. The ray passes through the unmasked rectangle.")]
|
||||
[SerializeField] Unmask m_TargetUnmask;
|
||||
|
||||
|
||||
//################################
|
||||
// Public Members.
|
||||
//################################
|
||||
/// <summary>
|
||||
/// Target unmask component. Ray through the unmasked rectangle.
|
||||
/// </summary>
|
||||
public Unmask targetUnmask{ get { return m_TargetUnmask; } set { m_TargetUnmask = value; } }
|
||||
|
||||
/// <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 bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
|
||||
{
|
||||
// Skip if deactived.
|
||||
if (!isActiveAndEnabled || !m_TargetUnmask || !m_TargetUnmask.isActiveAndEnabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get world corners for the target.
|
||||
(m_TargetUnmask.transform as RectTransform).GetWorldCorners(s_WorldCorners);
|
||||
|
||||
// Convert to screen positions.
|
||||
var cam = eventCamera ?? Camera.main;
|
||||
var p = cam.WorldToScreenPoint(sp);
|
||||
var a = cam.WorldToScreenPoint(s_WorldCorners[0]);
|
||||
var b = cam.WorldToScreenPoint(s_WorldCorners[1]);
|
||||
var c = cam.WorldToScreenPoint(s_WorldCorners[2]);
|
||||
var d = cam.WorldToScreenPoint(s_WorldCorners[3]);
|
||||
|
||||
// check left/right side
|
||||
var ab = Cross(p - a, b - a) < 0.0;
|
||||
var bc = Cross(p - b, c - b) < 0.0;
|
||||
var cd = Cross(p - c, d - c) < 0.0;
|
||||
var da = Cross(p - d, a - d) < 0.0;
|
||||
|
||||
// check inside
|
||||
return ab ^ bc ||bc ^ cd ||cd ^ da;
|
||||
}
|
||||
|
||||
|
||||
//################################
|
||||
// Private Members.
|
||||
//################################
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the object becomes enabled and active.
|
||||
/// </summary>
|
||||
void OnEnable()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cross for Vector2.
|
||||
/// </summary>
|
||||
float Cross(Vector2 a, Vector2 b)
|
||||
{
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0bb9714b62a114d45b65f30fc946ea5c
|
||||
timeCreated: 1539226167
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue