GoWrapper.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. using UnityEngine;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. namespace FairyGUI
  6. {
  7. /// <summary>
  8. /// GoWrapper is class for wrapping common gameobject into UI display list.
  9. /// </summary>
  10. public class GoWrapper : DisplayObject
  11. {
  12. [Obsolete("No need to manually set this flag anymore, coz it will be handled automatically.")]
  13. public bool supportStencil;
  14. public event Action<UpdateContext> onUpdate;
  15. public Action<Dictionary<Material, Material>> customCloneMaterials;
  16. public Action customRecoverMaterials;
  17. protected GameObject _wrapTarget;
  18. protected List<RendererInfo> _renderers;
  19. protected Dictionary<Material, Material> _materialsBackup;
  20. protected Canvas _canvas;
  21. protected bool _cloneMaterial;
  22. protected bool _shouldCloneMaterial;
  23. protected struct RendererInfo
  24. {
  25. public Renderer renderer;
  26. public Material[] materials;
  27. public int sortingOrder;
  28. }
  29. protected static List<Transform> helperTransformList = new List<Transform>();
  30. /// <summary>
  31. ///
  32. /// </summary>
  33. public GoWrapper()
  34. {
  35. // _flags |= Flags.SkipBatching;
  36. _renderers = new List<RendererInfo>();
  37. _materialsBackup = new Dictionary<Material, Material>();
  38. CreateGameObject("GoWrapper");
  39. }
  40. /// <summary>
  41. ///
  42. /// </summary>
  43. /// <param name="go">包装对象。</param>
  44. public GoWrapper(GameObject go) : this()
  45. {
  46. SetWrapTarget(go, false);
  47. }
  48. /// <summary>
  49. /// 设置包装对象。注意如果原来有包装对象,设置新的包装对象后,原来的包装对象只会被删除引用,但不会被销毁。
  50. /// 对象包含的所有材质不会被复制,如果材质已经是公用的,这可能影响到其他对象。如果希望自动复制,改为使用SetWrapTarget(target, true)设置。
  51. /// </summary>
  52. public GameObject wrapTarget
  53. {
  54. get { return _wrapTarget; }
  55. set { SetWrapTarget(value, false); }
  56. }
  57. [Obsolete("setWrapTarget is deprecated. Use SetWrapTarget instead.")]
  58. public void setWrapTarget(GameObject target, bool cloneMaterial)
  59. {
  60. SetWrapTarget(target, cloneMaterial);
  61. }
  62. /// <summary>
  63. /// 设置包装对象。注意如果原来有包装对象,设置新的包装对象后,原来的包装对象只会被删除引用,但不会被销毁。
  64. /// </summary>
  65. /// <param name="target"></param>
  66. /// <param name="cloneMaterial">如果true,则复制材质,否则直接使用sharedMaterial。</param>
  67. public void SetWrapTarget(GameObject target, bool cloneMaterial)
  68. {
  69. // set Flags.SkipBatching only target not null
  70. if (target == null) _flags &= ~Flags.SkipBatching;
  71. else _flags |= Flags.SkipBatching;
  72. InvalidateBatchingState();
  73. RecoverMaterials();
  74. _cloneMaterial = cloneMaterial;
  75. if (_wrapTarget != null)
  76. _wrapTarget.transform.SetParent(null, false);
  77. _canvas = null;
  78. _wrapTarget = target;
  79. _shouldCloneMaterial = false;
  80. _renderers.Clear();
  81. if (_wrapTarget != null)
  82. {
  83. _wrapTarget.transform.SetParent(this.cachedTransform, false);
  84. _canvas = _wrapTarget.GetComponent<Canvas>();
  85. if (_canvas != null)
  86. {
  87. _canvas.renderMode = RenderMode.WorldSpace;
  88. _canvas.worldCamera = StageCamera.main;
  89. _canvas.overrideSorting = true;
  90. RectTransform rt = _canvas.GetComponent<RectTransform>();
  91. rt.pivot = new Vector2(0, 1);
  92. rt.position = new Vector3(0, 0, 0);
  93. this.SetSize(rt.rect.width, rt.rect.height);
  94. }
  95. else
  96. {
  97. CacheRenderers();
  98. this.SetSize(0, 0);
  99. }
  100. SetGoLayers(this.layer);
  101. }
  102. }
  103. /// <summary>
  104. /// GoWrapper will cache all renderers of your gameobject on constructor.
  105. /// If your gameobject change laterly, call this function to update the cache.
  106. /// GoWrapper会在构造函数里查询你的gameobject所有的Renderer并保存。如果你的gameobject
  107. /// 后续发生了改变,调用这个函数通知GoWrapper重新查询和保存。
  108. /// </summary>
  109. public void CacheRenderers()
  110. {
  111. if (_canvas != null)
  112. return;
  113. RecoverMaterials();
  114. _renderers.Clear();
  115. Renderer[] items = _wrapTarget.GetComponentsInChildren<Renderer>(true);
  116. int cnt = items.Length;
  117. _renderers.Capacity = cnt;
  118. for (int i = 0; i < cnt; i++)
  119. {
  120. Renderer r = items[i];
  121. Material[] mats = r.sharedMaterials;
  122. RendererInfo ri = new RendererInfo()
  123. {
  124. renderer = r,
  125. materials = mats,
  126. sortingOrder = r.sortingOrder
  127. };
  128. _renderers.Add(ri);
  129. if (!_cloneMaterial && mats != null
  130. && ((r is SkinnedMeshRenderer) || (r is MeshRenderer)))
  131. {
  132. int mcnt = mats.Length;
  133. for (int j = 0; j < mcnt; j++)
  134. {
  135. Material mat = mats[j];
  136. if (mat != null && mat.renderQueue != 3000) //Set the object rendering in Transparent Queue as UI objects
  137. mat.renderQueue = 3000;
  138. }
  139. }
  140. }
  141. _renderers.Sort((RendererInfo c1, RendererInfo c2) =>
  142. {
  143. return c1.sortingOrder - c2.sortingOrder;
  144. });
  145. _shouldCloneMaterial = _cloneMaterial;
  146. }
  147. void CloneMaterials()
  148. {
  149. _shouldCloneMaterial = false;
  150. int cnt = _renderers.Count;
  151. for (int i = 0; i < cnt; i++)
  152. {
  153. RendererInfo ri = _renderers[i];
  154. Material[] mats = ri.materials;
  155. if (mats == null)
  156. continue;
  157. bool shouldSetRQ = (ri.renderer is SkinnedMeshRenderer) || (ri.renderer is MeshRenderer);
  158. int mcnt = mats.Length;
  159. for (int j = 0; j < mcnt; j++)
  160. {
  161. Material mat = mats[j];
  162. if (mat == null)
  163. continue;
  164. //确保相同的材质不会复制两次
  165. Material newMat;
  166. if (!_materialsBackup.TryGetValue(mat, out newMat))
  167. {
  168. newMat = new Material(mat);
  169. _materialsBackup[mat] = newMat;
  170. }
  171. mats[j] = newMat;
  172. if (shouldSetRQ && mat.renderQueue != 3000) //Set the object rendering in Transparent Queue as UI objects
  173. newMat.renderQueue = 3000;
  174. }
  175. if (customCloneMaterials != null)
  176. customCloneMaterials.Invoke(_materialsBackup);
  177. else if (ri.renderer != null)
  178. ri.renderer.sharedMaterials = mats;
  179. }
  180. }
  181. void RecoverMaterials()
  182. {
  183. if (_materialsBackup.Count == 0)
  184. return;
  185. int cnt = _renderers.Count;
  186. for (int i = 0; i < cnt; i++)
  187. {
  188. RendererInfo ri = _renderers[i];
  189. if (ri.renderer == null)
  190. continue;
  191. Material[] mats = ri.materials;
  192. if (mats == null)
  193. continue;
  194. int mcnt = mats.Length;
  195. for (int j = 0; j < mcnt; j++)
  196. {
  197. Material mat = mats[j];
  198. foreach (KeyValuePair<Material, Material> kv in _materialsBackup)
  199. {
  200. if (kv.Value == mat)
  201. mats[j] = kv.Key;
  202. }
  203. }
  204. if (customRecoverMaterials != null)
  205. customRecoverMaterials.Invoke();
  206. else
  207. ri.renderer.sharedMaterials = mats;
  208. }
  209. foreach (KeyValuePair<Material, Material> kv in _materialsBackup)
  210. Material.DestroyImmediate(kv.Value);
  211. _materialsBackup.Clear();
  212. }
  213. public override int renderingOrder
  214. {
  215. get
  216. {
  217. return base.renderingOrder;
  218. }
  219. set
  220. {
  221. base.renderingOrder = value;
  222. if (_canvas != null)
  223. _canvas.sortingOrder = value;
  224. else
  225. {
  226. int cnt = _renderers.Count;
  227. for (int i = 0; i < cnt; i++)
  228. {
  229. RendererInfo ri = _renderers[i];
  230. if (ri.renderer != null)
  231. {
  232. if (i != 0 && _renderers[i].sortingOrder != _renderers[i - 1].sortingOrder)
  233. value = UpdateContext.current.renderingOrder++;
  234. ri.renderer.sortingOrder = value;
  235. }
  236. }
  237. }
  238. }
  239. }
  240. override protected bool SetLayer(int value, bool fromParent)
  241. {
  242. if (base.SetLayer(value, fromParent))
  243. {
  244. SetGoLayers(value);
  245. return true;
  246. }
  247. else
  248. return false;
  249. }
  250. protected void SetGoLayers(int layer)
  251. {
  252. if (_wrapTarget == null)
  253. return;
  254. _wrapTarget.GetComponentsInChildren<Transform>(true, helperTransformList);
  255. int cnt = helperTransformList.Count;
  256. for (int i = 0; i < cnt; i++)
  257. helperTransformList[i].gameObject.layer = layer;
  258. helperTransformList.Clear();
  259. }
  260. override public void Update(UpdateContext context)
  261. {
  262. if (onUpdate != null)
  263. onUpdate(context);
  264. if (_shouldCloneMaterial)
  265. CloneMaterials();
  266. ApplyClipping(context);
  267. base.Update(context);
  268. }
  269. private List<Material> helperMaterials = new List<Material>();
  270. virtual protected void ApplyClipping(UpdateContext context)
  271. {
  272. #if UNITY_2018_2_OR_NEWER
  273. int cnt = _renderers.Count;
  274. for (int i = 0; i < cnt; i++)
  275. {
  276. Renderer renderer = _renderers[i].renderer;
  277. if (renderer == null)
  278. continue;
  279. if (customCloneMaterials != null)
  280. helperMaterials.AddRange(_materialsBackup.Values);
  281. else
  282. renderer.GetSharedMaterials(helperMaterials);
  283. int cnt2 = helperMaterials.Count;
  284. for (int j = 0; j < cnt2; j++)
  285. {
  286. Material mat = helperMaterials[j];
  287. if (mat != null)
  288. context.ApplyClippingProperties(mat, false);
  289. }
  290. helperMaterials.Clear();
  291. }
  292. #else
  293. int cnt = _renderers.Count;
  294. for (int i = 0; i < cnt; i++)
  295. {
  296. Material[] mats = _renderers[i].materials;
  297. if (mats == null)
  298. continue;
  299. int cnt2 = mats.Length;
  300. for (int j = 0; j < cnt2; j++)
  301. {
  302. Material mat = mats[j];
  303. if (mat != null)
  304. context.ApplyClippingProperties(mat, false);
  305. }
  306. }
  307. #endif
  308. }
  309. public override void Dispose()
  310. {
  311. if ((_flags & Flags.Disposed) != 0)
  312. return;
  313. if (_wrapTarget != null)
  314. {
  315. UnityEngine.Object.Destroy(_wrapTarget);
  316. _wrapTarget = null;
  317. if (_materialsBackup.Count > 0)
  318. { //如果有备份,说明材质是复制出来的,应该删除
  319. foreach (KeyValuePair<Material, Material> kv in _materialsBackup)
  320. Material.DestroyImmediate(kv.Value);
  321. }
  322. }
  323. _renderers = null;
  324. _materialsBackup = null;
  325. _canvas = null;
  326. customCloneMaterials = null;
  327. customRecoverMaterials = null;
  328. base.Dispose();
  329. }
  330. }
  331. }