GoWrapper.cs 12 KB

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