Outlinable.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using System;
  4. using System.Security.Cryptography;
  5. namespace EPOOutline
  6. {
  7. public enum DilateRenderMode
  8. {
  9. PostProcessing,
  10. EdgeShift
  11. }
  12. public enum RenderStyle
  13. {
  14. Single = 1,
  15. FrontBack = 2
  16. }
  17. [Flags]
  18. public enum OutlinableDrawingMode
  19. {
  20. Normal = 1,
  21. ZOnly = 2,
  22. GenericMask = 4,
  23. Obstacle = 8,
  24. Mask = 16
  25. }
  26. [Flags]
  27. public enum RenderersAddingMode
  28. {
  29. All = -1,
  30. None = 0,
  31. MeshRenderer = 1,
  32. SkinnedMeshRenderer = 2,
  33. SpriteRenderer = 4,
  34. Others = 4096
  35. }
  36. public enum BoundsMode
  37. {
  38. Default,
  39. ForceRecalculate,
  40. Manual
  41. }
  42. public enum ComplexMaskingMode
  43. {
  44. None,
  45. ObstaclesMode,
  46. MaskingMode
  47. }
  48. [ExecuteAlways]
  49. public class Outlinable : MonoBehaviour
  50. {
  51. private static List<TargetStateListener> tempListeners = new List<TargetStateListener>();
  52. private static HashSet<Outlinable> outlinables = new HashSet<Outlinable>();
  53. [System.Serializable]
  54. public class OutlineProperties
  55. {
  56. #pragma warning disable CS0649
  57. [SerializeField]
  58. private bool enabled = true;
  59. public bool Enabled
  60. {
  61. get
  62. {
  63. return enabled;
  64. }
  65. set
  66. {
  67. enabled = value;
  68. }
  69. }
  70. [SerializeField]
  71. private Color color = Color.yellow;
  72. public Color Color
  73. {
  74. get
  75. {
  76. return color;
  77. }
  78. set
  79. {
  80. color = value;
  81. }
  82. }
  83. [SerializeField]
  84. [Range(0.0f, 1.0f)]
  85. private float dilateShift = 1.0f;
  86. public float DilateShift
  87. {
  88. get
  89. {
  90. return dilateShift;
  91. }
  92. set
  93. {
  94. dilateShift = value;
  95. }
  96. }
  97. [SerializeField]
  98. [Range(0.0f, 1.0f)]
  99. private float blurShift = 1.0f;
  100. public float BlurShift
  101. {
  102. get
  103. {
  104. return blurShift;
  105. }
  106. set
  107. {
  108. blurShift = value;
  109. }
  110. }
  111. [SerializeField, SerializedPassInfo("Fill style", "Hidden/EPO/Fill/")]
  112. private SerializedPass fillPass = new SerializedPass();
  113. public SerializedPass FillPass
  114. {
  115. get
  116. {
  117. return fillPass;
  118. }
  119. }
  120. public void SetFillPass(SerializedPass pass)
  121. {
  122. fillPass = pass;
  123. }
  124. #pragma warning restore CS0649
  125. }
  126. [SerializeField]
  127. private ComplexMaskingMode complexMaskingMode;
  128. [SerializeField]
  129. private OutlinableDrawingMode drawingMode = OutlinableDrawingMode.Normal;
  130. [SerializeField]
  131. private int outlineLayer = 0;
  132. [SerializeField]
  133. private List<OutlineTarget> outlineTargets = new List<OutlineTarget>();
  134. [SerializeField]
  135. private RenderStyle renderStyle = RenderStyle.Single;
  136. #pragma warning disable CS0649
  137. [SerializeField]
  138. private OutlineProperties outlineParameters = new OutlineProperties();
  139. [SerializeField]
  140. private OutlineProperties backParameters = new OutlineProperties();
  141. [SerializeField]
  142. private OutlineProperties frontParameters = new OutlineProperties();
  143. private bool shouldValidateTargets = false;
  144. [SerializeField]
  145. private bool showOutlineTargets=false;
  146. #pragma warning restore CS0649
  147. public bool ShowOutLineTargets
  148. {
  149. get
  150. {
  151. return showOutlineTargets;
  152. }
  153. set
  154. {
  155. showOutlineTargets = value;
  156. }
  157. }
  158. public RenderStyle RenderStyle
  159. {
  160. get
  161. {
  162. return renderStyle;
  163. }
  164. set
  165. {
  166. renderStyle = value;
  167. }
  168. }
  169. public ComplexMaskingMode ComplexMaskingMode
  170. {
  171. get
  172. {
  173. return complexMaskingMode;
  174. }
  175. set
  176. {
  177. complexMaskingMode = value;
  178. }
  179. }
  180. public bool ComplexMaskingEnabled
  181. {
  182. get
  183. {
  184. return complexMaskingMode != ComplexMaskingMode.None;
  185. }
  186. }
  187. public OutlinableDrawingMode DrawingMode
  188. {
  189. get
  190. {
  191. return drawingMode;
  192. }
  193. set
  194. {
  195. drawingMode = value;
  196. }
  197. }
  198. public int OutlineLayer
  199. {
  200. get
  201. {
  202. return outlineLayer;
  203. }
  204. set
  205. {
  206. outlineLayer = value;
  207. }
  208. }
  209. public IReadOnlyList<OutlineTarget> OutlineTargets
  210. {
  211. get
  212. {
  213. return outlineTargets;
  214. }
  215. }
  216. public OutlineProperties OutlineParameters
  217. {
  218. get
  219. {
  220. return outlineParameters;
  221. }
  222. }
  223. public OutlineProperties BackParameters
  224. {
  225. get
  226. {
  227. return backParameters;
  228. }
  229. }
  230. public bool NeedFillMask
  231. {
  232. get
  233. {
  234. if ((drawingMode & OutlinableDrawingMode.Normal) == 0)
  235. return false;
  236. if (renderStyle == RenderStyle.FrontBack)
  237. return (frontParameters.Enabled || backParameters.Enabled) && (frontParameters.FillPass.Material != null || backParameters.FillPass.Material != null);
  238. else
  239. return false;
  240. }
  241. }
  242. public OutlineProperties FrontParameters
  243. {
  244. get
  245. {
  246. return frontParameters;
  247. }
  248. }
  249. public bool IsObstacle
  250. {
  251. get
  252. {
  253. return (drawingMode & OutlinableDrawingMode.Obstacle) != 0;
  254. }
  255. }
  256. public bool TryAddTarget(OutlineTarget target)
  257. {
  258. outlineTargets.Add(target);
  259. ValidateTargets();
  260. return true;
  261. }
  262. public void RemoveTarget(OutlineTarget target)
  263. {
  264. outlineTargets.Remove(target);
  265. if (target.renderer != null)
  266. {
  267. var listener = target.renderer.GetComponent<TargetStateListener>();
  268. if (listener == null)
  269. return;
  270. listener.RemoveCallback(this, UpdateVisibility);
  271. }
  272. }
  273. public OutlineTarget this[int index]
  274. {
  275. get
  276. {
  277. return outlineTargets[index];
  278. }
  279. set
  280. {
  281. outlineTargets[index] = value;
  282. ValidateTargets();
  283. }
  284. }
  285. private void Reset()
  286. {
  287. AddAllChildRenderersToRenderingList(RenderersAddingMode.SkinnedMeshRenderer | RenderersAddingMode.MeshRenderer | RenderersAddingMode.SpriteRenderer);
  288. }
  289. private void OnValidate()
  290. {
  291. outlineLayer = Mathf.Clamp(outlineLayer, 0, 63);
  292. shouldValidateTargets = true;
  293. }
  294. private void SubscribeToVisibilityChange(GameObject go)
  295. {
  296. var listener = go.GetComponent<TargetStateListener>();
  297. if (listener == null)
  298. {
  299. listener = go.AddComponent<TargetStateListener>();
  300. #if UNITY_EDITOR
  301. UnityEditor.EditorUtility.SetDirty(listener);
  302. UnityEditor.EditorUtility.SetDirty(go);
  303. #endif
  304. }
  305. listener.RemoveCallback(this, UpdateVisibility);
  306. listener.AddCallback(this, UpdateVisibility);
  307. listener.ForceUpdate();
  308. }
  309. private void UpdateVisibility()
  310. {
  311. if (!enabled)
  312. {
  313. outlinables.Remove(this);
  314. return;
  315. }
  316. outlineTargets.RemoveAll(x => x.renderer == null);
  317. foreach (var target in OutlineTargets)
  318. target.IsVisible = target.renderer.isVisible;
  319. outlineTargets.RemoveAll(x => x.renderer == null);
  320. foreach (var target in outlineTargets)
  321. {
  322. if (target.IsVisible)
  323. {
  324. outlinables.Add(this);
  325. return;
  326. }
  327. }
  328. outlinables.Remove(this);
  329. }
  330. private void OnEnable()
  331. {
  332. UpdateVisibility();
  333. }
  334. private void OnDisable()
  335. {
  336. outlinables.Remove(this);
  337. }
  338. private void Awake()
  339. {
  340. ValidateTargets();
  341. }
  342. private void ValidateTargets()
  343. {
  344. outlineTargets.RemoveAll(x => x.renderer == null);
  345. foreach (var target in outlineTargets)
  346. SubscribeToVisibilityChange(target.renderer.gameObject);
  347. }
  348. private void OnDestroy()
  349. {
  350. outlinables.Remove(this);
  351. }
  352. public static void GetAllActiveOutlinables(Camera camera, List<Outlinable> outlinablesList)
  353. {
  354. outlinablesList.Clear();
  355. foreach (var outlinable in outlinables)
  356. outlinablesList.Add(outlinable);
  357. }
  358. private int GetSubmeshCount(Renderer renderer)
  359. {
  360. if (renderer is MeshRenderer)
  361. return renderer.GetComponent<MeshFilter>().sharedMesh.subMeshCount;
  362. else if (renderer is SkinnedMeshRenderer)
  363. return (renderer as SkinnedMeshRenderer).sharedMesh.subMeshCount;
  364. else
  365. return 1;
  366. }
  367. [ContextMenu("ResetRenderer")]
  368. public void AddAllChildRenderersToRenderingList(RenderersAddingMode renderersAddingMode = RenderersAddingMode.All)
  369. {
  370. outlineTargets.Clear();
  371. var renderers = GetComponentsInChildren<Renderer>(true);
  372. foreach (var renderer in renderers)
  373. {
  374. if (!MatchingMode(renderer, renderersAddingMode))
  375. continue;
  376. var submeshesCount = GetSubmeshCount(renderer);
  377. for (var index = 0; index < submeshesCount; index++)
  378. TryAddTarget(new OutlineTarget(renderer, index));
  379. }
  380. }
  381. private void Update()
  382. {
  383. if (!shouldValidateTargets)
  384. return;
  385. shouldValidateTargets = false;
  386. ValidateTargets();
  387. }
  388. private bool MatchingMode(Renderer renderer, RenderersAddingMode mode)
  389. {
  390. return
  391. (!(renderer is MeshRenderer) && !(renderer is SkinnedMeshRenderer) && !(renderer is SpriteRenderer) && (mode & RenderersAddingMode.Others) != RenderersAddingMode.None) ||
  392. (renderer is MeshRenderer && (mode & RenderersAddingMode.MeshRenderer) != RenderersAddingMode.None) ||
  393. (renderer is SpriteRenderer && (mode & RenderersAddingMode.SpriteRenderer) != RenderersAddingMode.None) ||
  394. (renderer is SkinnedMeshRenderer && (mode & RenderersAddingMode.SkinnedMeshRenderer) != RenderersAddingMode.None);
  395. }
  396. #if UNITY_EDITOR
  397. public void OnDrawGizmosSelected()
  398. {
  399. foreach (var target in outlineTargets)
  400. {
  401. if (target.Renderer == null || target.BoundsMode != BoundsMode.Manual)
  402. continue;
  403. Gizmos.matrix = target.Renderer.transform.localToWorldMatrix;
  404. Gizmos.color = new Color(1.0f, 0.5f, 0.0f, 0.2f);
  405. var size = target.Bounds.size;
  406. var scale = target.Renderer.transform.localScale;
  407. size.x /= scale.x;
  408. size.y /= scale.y;
  409. size.z /= scale.z;
  410. Gizmos.DrawCube(target.Bounds.center, size);
  411. Gizmos.DrawWireCube(target.Bounds.center, size);
  412. }
  413. }
  414. #endif
  415. }
  416. }