GetParticleEffectData.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #if UNITY_EDITOR
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Reflection;
  6. using UnityEditor;
  7. using UnityEngine;
  8. using UnityEngine.Profiling;
  9. /// <summary>
  10. /// 处理特效整体相关的数据
  11. /// </summary>
  12. public class GetParticleEffectData {
  13. static int m_MaxDrawCall = 0;
  14. public static int GetRuntimeMemorySize(GameObject go, out int textureCount)
  15. {
  16. var textures = new List<Texture>();
  17. textureCount = 0;
  18. int sumSize = 0;
  19. var meshRendererlist = go.GetComponentsInChildren<ParticleSystemRenderer>(true);
  20. foreach (ParticleSystemRenderer item in meshRendererlist)
  21. {
  22. if (item.sharedMaterial)
  23. {
  24. Texture texture = item.sharedMaterial.mainTexture;
  25. if (texture && !textures.Contains(texture))
  26. {
  27. textures.Add(texture);
  28. textureCount++;
  29. sumSize = sumSize + GetStorageMemorySize(texture);
  30. }
  31. }
  32. }
  33. return sumSize;
  34. }
  35. private static int GetStorageMemorySize(Texture texture)
  36. {
  37. return (int)InvokeInternalAPI("UnityEditor.TextureUtil", "GetStorageMemorySize", texture);
  38. }
  39. private static object InvokeInternalAPI(string type, string method, params object[] parameters)
  40. {
  41. var assembly = typeof(AssetDatabase).Assembly;
  42. var custom = assembly.GetType(type);
  43. var methodInfo = custom.GetMethod(method, BindingFlags.Public | BindingFlags.Static);
  44. return methodInfo != null ? methodInfo.Invoke(null, parameters) : 0;
  45. }
  46. public static string GetGetRuntimeMemorySizeStr(GameObject go)
  47. {
  48. int maxTextureCount = 5;
  49. int maxMemorySize = 1000 * 1024;
  50. int textureCount;
  51. int memorySize = GetRuntimeMemorySize(go, out textureCount);
  52. string memorySizeStr = EditorUtility.FormatBytes(memorySize);
  53. string maxMemorySizeStr = EditorUtility.FormatBytes(maxMemorySize);
  54. if (maxMemorySize > memorySize)
  55. memorySizeStr = string.Format("<color=green>{0}</color>", memorySizeStr);
  56. else
  57. memorySizeStr = string.Format("<color=red>{0}</color>", memorySizeStr);
  58. return string.Format("贴图所占用的内存:{0} 建议:<{1}\n贴图数量:{2} 建议:<{3}", memorySizeStr, maxMemorySizeStr, FormatColorMax(textureCount, maxTextureCount), maxTextureCount);
  59. }
  60. public static string GetParticleSystemCount(GameObject go)
  61. {
  62. int max = 5;
  63. var particleSystems = go.GetComponentsInChildren<ParticleSystem>(true);
  64. return string.Format("特效中所有粒子系统组件数量:{0} 建议:<{1}", FormatColorMax(particleSystems.Length, max), max);
  65. }
  66. public static int GetOnlyParticleEffecDrawCall()
  67. {
  68. //因为Camera 实际上渲染了两次,一次用作取样,一次用作显示。 狂飙这里给出了详细的说明:https://networm.me/2019/07/28/unity-particle-effect-profiler/#drawcall-%E6%95%B0%E5%80%BC%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AF%94%E5%AE%9E%E9%99%85%E5%A4%A7-2-%E5%80%8D
  69. int drawCall = UnityEditor.UnityStats.batches / 2;
  70. if (m_MaxDrawCall<drawCall)
  71. {
  72. m_MaxDrawCall = drawCall;
  73. }
  74. return drawCall;
  75. }
  76. public static string GetOnlyParticleEffecDrawCallStr()
  77. {
  78. int max = 10;
  79. return string.Format("DrawCall: {0} 最高:{1} 建议:<{2}", FormatColorMax(GetOnlyParticleEffecDrawCall(), max), FormatColorMax(m_MaxDrawCall, max), max);
  80. }
  81. public static string GetPixDrawAverageStr(ParticleEffectScript particleEffectGo)
  82. {
  83. //index = 0:默认按高品质的算,这里你可以根本你们项目的品质进行修改。
  84. EffectEvlaData[] effectEvlaData = particleEffectGo.GetEffectEvlaData();
  85. int pixDrawAverage = effectEvlaData[0].GetPixDrawAverage();
  86. return string.Format("特效原填充像素点:{0}", FormatColorValue(pixDrawAverage));
  87. }
  88. public static string GetPixActualDrawAverageStr(ParticleEffectScript particleEffectGo)
  89. {
  90. EffectEvlaData[] effectEvlaData = particleEffectGo.GetEffectEvlaData();
  91. int pixActualDrawAverage = effectEvlaData[0].GetPixActualDrawAverage();
  92. return string.Format("特效实际填充像素点:{0}", FormatColorValue(pixActualDrawAverage));
  93. }
  94. public static string GetPixRateStr(ParticleEffectScript particleEffectGo)
  95. {
  96. int max = 4;
  97. EffectEvlaData[] effectEvlaData = particleEffectGo.GetEffectEvlaData();
  98. int pixRate = effectEvlaData[0].GetPixRate();
  99. return string.Format("平均每像素overdraw率:{0} 建议:<{1}", FormatColorMax(pixRate, max), max);
  100. }
  101. public static string GetParticleCountStr(ParticleEffectScript particleEffectGo)
  102. {
  103. int max = 50;
  104. return string.Format("粒子数量:{0} 最高:{1} 建议:<{2}", FormatColorMax(particleEffectGo.GetParticleCount(), max), FormatColorMax(particleEffectGo.GetMaxParticleCount(), max), max);
  105. }
  106. public static string GetCullingSupportedString(GameObject go)
  107. {
  108. var particleSystems = go.GetComponentsInChildren<ParticleSystem>(true);
  109. string text = "";
  110. foreach (ParticleSystem item in particleSystems)
  111. {
  112. string str = CheckCulling(item);
  113. if (!string.IsNullOrEmpty(str))
  114. {
  115. text += item.gameObject.name + ":" + str + "\n\n";
  116. }
  117. }
  118. return text;
  119. }
  120. static string CheckCulling(ParticleSystem particleSystem)
  121. {
  122. string text = "";
  123. if (particleSystem.collision.enabled)
  124. {
  125. text += "\n勾选了 Collision";
  126. }
  127. if (particleSystem.emission.enabled)
  128. {
  129. if (particleSystem.emission.rateOverDistance.curveMultiplier != 0)
  130. {
  131. text += "\nEmission使用了Current(非线性运算)";
  132. }
  133. }
  134. if (particleSystem.externalForces.enabled)
  135. {
  136. text += "\n勾选了 External Forces";
  137. }
  138. if (particleSystem.forceOverLifetime.enabled)
  139. {
  140. if (GetIsRandomized(particleSystem.forceOverLifetime.x)
  141. || GetIsRandomized(particleSystem.forceOverLifetime.y)
  142. || GetIsRandomized(particleSystem.forceOverLifetime.z)
  143. || particleSystem.forceOverLifetime.randomized)
  144. {
  145. text += "\nForce Over Lifetime使用了Current(非线性运算)";
  146. }
  147. }
  148. if (particleSystem.inheritVelocity.enabled)
  149. {
  150. if (GetIsRandomized(particleSystem.inheritVelocity.curve))
  151. {
  152. text += "\nInherit Velocity使用了Current(非线性运算)";
  153. }
  154. }
  155. if (particleSystem.noise.enabled)
  156. {
  157. text += "\n勾选了 Noise";
  158. }
  159. if (particleSystem.rotationBySpeed.enabled)
  160. {
  161. text += "\n勾选了 Rotation By Speed";
  162. }
  163. if (particleSystem.rotationOverLifetime.enabled)
  164. {
  165. if (GetIsRandomized(particleSystem.rotationOverLifetime.x)
  166. || GetIsRandomized(particleSystem.rotationOverLifetime.y)
  167. || GetIsRandomized(particleSystem.rotationOverLifetime.z))
  168. {
  169. text += "\nRotation Over Lifetime使用了Current(非线性运算)";
  170. }
  171. }
  172. if (particleSystem.shape.enabled)
  173. {
  174. ParticleSystemShapeType shapeType = (ParticleSystemShapeType)particleSystem.shape.shapeType;
  175. switch (shapeType)
  176. {
  177. case ParticleSystemShapeType.Cone:
  178. case ParticleSystemShapeType.ConeVolume:
  179. #if UNITY_2017_1_OR_NEWER
  180. case ParticleSystemShapeType.Donut:
  181. #endif
  182. case ParticleSystemShapeType.Circle:
  183. if(particleSystem.shape.arcMode != ParticleSystemShapeMultiModeValue.Random)
  184. {
  185. text += "\nShape的Circle-Arc使用了Random模式";
  186. }
  187. break;
  188. case ParticleSystemShapeType.SingleSidedEdge:
  189. if (particleSystem.shape.radiusMode != ParticleSystemShapeMultiModeValue.Random)
  190. {
  191. text += "\nShape的Edge-Radius使用了Random模式";
  192. }
  193. break;
  194. default:
  195. break;
  196. }
  197. }
  198. if (particleSystem.subEmitters.enabled)
  199. {
  200. text += "\n勾选了 SubEmitters";
  201. }
  202. if (particleSystem.trails.enabled)
  203. {
  204. text += "\n勾选了 Trails";
  205. }
  206. if (particleSystem.trigger.enabled)
  207. {
  208. text += "\n勾选了 Trigger";
  209. }
  210. if (particleSystem.velocityOverLifetime.enabled)
  211. {
  212. if (GetIsRandomized(particleSystem.velocityOverLifetime.x)
  213. || GetIsRandomized(particleSystem.velocityOverLifetime.y)
  214. || GetIsRandomized(particleSystem.velocityOverLifetime.z))
  215. {
  216. text += "\nVelocity Over Lifetime使用了Current(非线性运算)";
  217. }
  218. }
  219. if (particleSystem.limitVelocityOverLifetime.enabled)
  220. {
  221. text += "\n勾选了 Limit Velocity Over Lifetime";
  222. }
  223. if (particleSystem.main.simulationSpace != ParticleSystemSimulationSpace.Local)
  224. {
  225. text += "\nSimulationSpace 不等于 Local";
  226. }
  227. if (particleSystem.main.gravityModifierMultiplier != 0)
  228. {
  229. text += "\nGravityModifier 不等于0";
  230. }
  231. return text;
  232. }
  233. static bool GetIsRandomized(ParticleSystem.MinMaxCurve minMaxCurve)
  234. {
  235. bool flag = AnimationCurveSupportsProcedural(minMaxCurve.curveMax);
  236. bool result;
  237. if (minMaxCurve.mode != ParticleSystemCurveMode.TwoCurves && minMaxCurve.mode != ParticleSystemCurveMode.TwoConstants)
  238. {
  239. result = flag;
  240. }
  241. else
  242. {
  243. bool flag2 = AnimationCurveSupportsProcedural(minMaxCurve.curveMin);
  244. result = (flag && flag2);
  245. }
  246. return result;
  247. }
  248. static bool AnimationCurveSupportsProcedural(AnimationCurve curve)
  249. {
  250. //switch (AnimationUtility.IsValidPolynomialCurve(curve)) //保护级别,无法访问,靠
  251. //{
  252. // case AnimationUtility.PolynomialValid.Valid:
  253. // return true;
  254. // case AnimationUtility.PolynomialValid.InvalidPreWrapMode:
  255. // break;
  256. // case AnimationUtility.PolynomialValid.InvalidPostWrapMode:
  257. // break;
  258. // case AnimationUtility.PolynomialValid.TooManySegments:
  259. // break;
  260. //}
  261. return false; //只能默认返回false了
  262. }
  263. static string FormatColorValue(int value)
  264. {
  265. return string.Format("<color=green>{0}</color>", value);
  266. }
  267. static string FormatColorMax(int value, int max)
  268. {
  269. if (max > value)
  270. return string.Format("<color=green>{0}</color>", value);
  271. else
  272. return string.Format("<color=red>{0}</color>", value);
  273. }
  274. }
  275. #endif