From 9d7d8f6a6635885da849f8987ffbec41ac24862d Mon Sep 17 00:00:00 2001 From: mob-sakai Date: Sun, 14 Oct 2018 16:51:54 +0900 Subject: [PATCH] Impl unmask --- CHANGELOG.md | 1 + CHANGELOG.md.meta | 8 ++ LICENSE.txt | 1 + LICENSE.txt.meta | 8 ++ README.md | 1 + README.md.meta | 8 ++ Scripts.meta | 9 ++ Scripts/Unmask.cs | 157 ++++++++++++++++++++++++++++ Scripts/Unmask.cs.meta | 12 +++ Scripts/UnmaskRaycastFilter.cs | 92 ++++++++++++++++ Scripts/UnmaskRaycastFilter.cs.meta | 12 +++ 11 files changed, 309 insertions(+) create mode 120000 CHANGELOG.md create mode 100644 CHANGELOG.md.meta create mode 120000 LICENSE.txt create mode 100644 LICENSE.txt.meta create mode 120000 README.md create mode 100644 README.md.meta create mode 100644 Scripts.meta create mode 100644 Scripts/Unmask.cs create mode 100644 Scripts/Unmask.cs.meta create mode 100644 Scripts/UnmaskRaycastFilter.cs create mode 100644 Scripts/UnmaskRaycastFilter.cs.meta diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 120000 index 0000000..cd67e22 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +./../../../../CHANGELOG.md \ No newline at end of file diff --git a/CHANGELOG.md.meta b/CHANGELOG.md.meta new file mode 100644 index 0000000..dd3698c --- /dev/null +++ b/CHANGELOG.md.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fbca627d531eb4ca9b5846c638709e4c +timeCreated: 1539214410 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.txt b/LICENSE.txt new file mode 120000 index 0000000..fff8277 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1 @@ +./../../../../LICENSE.txt \ No newline at end of file diff --git a/LICENSE.txt.meta b/LICENSE.txt.meta new file mode 100644 index 0000000..3d692a6 --- /dev/null +++ b/LICENSE.txt.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cefd86cfe94614a08ac447d0a9ec6ad3 +timeCreated: 1539214411 +licenseType: Pro +TextScriptImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md new file mode 120000 index 0000000..7d6adfb --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +./../../../../README.md \ No newline at end of file diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..7c24bcd --- /dev/null +++ b/README.md.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c5f8a1ac798e442eb3c77b05470878d +timeCreated: 1539214410 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts.meta b/Scripts.meta new file mode 100644 index 0000000..051a40b --- /dev/null +++ b/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 50a872063d2754fcd9d092eab7677003 +folderAsset: yes +timeCreated: 1539214485 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Unmask.cs b/Scripts/Unmask.cs new file mode 100644 index 0000000..6d4f53a --- /dev/null +++ b/Scripts/Unmask.cs @@ -0,0 +1,157 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.UI; + + +namespace Coffee.UIExtensions +{ + /// + /// Reverse masking for parent Mask component. + /// + [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. + //################################ + /// + /// The graphic associated with the unmask. + /// + public Graphic graphic{ get { return _graphic ?? (_graphic = GetComponent()); } } + + /// + /// Fit graphic's transform to target transform on LateUpdate. + /// + public RectTransform autoFitTarget{ get { return m_AutoFitTarget; } set { m_AutoFitTarget = value; } } + + /// + /// Show the graphic that is associated with the unmask render area. + /// + public bool showUnmaskGraphic + { + get { return m_ShowUnmaskGraphic; } + set + { + m_ShowUnmaskGraphic = value; + SetDirty(); + } + } + + /// + /// Perform material modification in this function. + /// + /// Modified material. + /// Configured Material. + 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; + } + + /// + /// Fit to target transform. + /// + /// Target transform. + 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; + + /// + /// This function is called when the object becomes enabled and active. + /// + void OnEnable() + { + if (m_AutoFitTarget) + { + FitTo(m_AutoFitTarget); + } + SetDirty(); + } + + /// + /// This function is called when the behaviour becomes disabled () or inactive. + /// + void OnDisable() + { + StencilMaterial.Remove(_unmaskMaterial); + _unmaskMaterial = null; + SetDirty(); + } + + /// + /// LateUpdate is called every frame, if the Behaviour is enabled. + /// + void LateUpdate() + { + if (m_AutoFitTarget) + { + FitTo(m_AutoFitTarget); + } + } + + /// + /// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only). + /// + void OnValidate() + { + SetDirty(); + } + + /// + /// Mark the graphic as dirty. + /// + void SetDirty() + { + if (graphic) + { + graphic.SetMaterialDirty(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Unmask.cs.meta b/Scripts/Unmask.cs.meta new file mode 100644 index 0000000..c90b296 --- /dev/null +++ b/Scripts/Unmask.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f752d3a51152f4e44a3ebe45ae24abcc +timeCreated: 1539214502 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/UnmaskRaycastFilter.cs b/Scripts/UnmaskRaycastFilter.cs new file mode 100644 index 0000000..5618ab7 --- /dev/null +++ b/Scripts/UnmaskRaycastFilter.cs @@ -0,0 +1,92 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + + +namespace Coffee.UIExtensions +{ + /// + /// Unmask Raycast Filter. + /// The ray passes through the unmasked rectangle. + /// + [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. + //################################ + /// + /// Target unmask component. Ray through the unmasked rectangle. + /// + public Unmask targetUnmask{ get { return m_TargetUnmask; } set { m_TargetUnmask = value; } } + + /// + /// Given a point and a camera is the raycast valid. + /// + /// Valid. + /// Screen position. + /// Raycast camera. + 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. + //################################ + + /// + /// This function is called when the object becomes enabled and active. + /// + void OnEnable() + { + } + + /// + /// Cross for Vector2. + /// + float Cross(Vector2 a, Vector2 b) + { + return a.x * b.y - a.y * b.x; + } + } +} \ No newline at end of file diff --git a/Scripts/UnmaskRaycastFilter.cs.meta b/Scripts/UnmaskRaycastFilter.cs.meta new file mode 100644 index 0000000..6c5c3a4 --- /dev/null +++ b/Scripts/UnmaskRaycastFilter.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0bb9714b62a114d45b65f30fc946ea5c +timeCreated: 1539226167 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: